import sys
import os
import pandas as pd
import numpy as np
import re
from PyQt6.QtWidgets import (QApplication, QMainWindow, QWidget, QVBoxLayout, QHBoxLayout, 
                             QPushButton, QListWidget, QTextEdit, QLabel, QLineEdit, 
                             QComboBox, QCheckBox, QSpinBox, QFileDialog, QMessageBox,
                             QTabWidget, QTableWidget, QTableWidgetItem, QProgressBar,
                             QSplitter, QFrame, QGroupBox, QCompleter, QDialog, QHeaderView)
from PyQt6.QtCore import Qt, QThread, pyqtSignal
from PyQt6.QtGui import QFont, QPalette, QColor
import sqlite3
import csv
import json
from datetime import datetime

class PhoneValidator:
    """手机号码验证器"""
    
    @staticmethod
    def is_valid_phone(phone):
        """验证手机号码格式"""
        # 中国手机号码格式：1开头，11位数字
        pattern = r'^1[3-9]\d{9}$'
        return bool(re.match(pattern, str(phone)))
    
    @staticmethod
    def get_operator(phone):
        """根据手机号获取运营商"""
        if not PhoneValidator.is_valid_phone(phone):
            return "无效号码"
        
        prefix = str(phone)[:3]
        if prefix in ['130', '131', '132', '155', '156', '166', '175', '176', '185', '186']:
            return "中国联通"
        elif prefix in ['133', '149', '153', '173', '177', '180', '181', '189', '199']:
            return "中国电信"
        elif prefix in ['134', '135', '136', '137', '138', '139', '147', '150', '151', '152', 
                       '157', '158', '159', '172', '178', '182', '183', '184', '187', '188', '198']:
            return "中国移动"
        else:
            return "未知运营商"
    
    @staticmethod
    def get_city(phone):
        """根据手机号获取城市信息"""
        if not PhoneValidator.is_valid_phone(phone):
            return "无效号码"
        
        # 加载系统数据库
        db_manager = DatabaseManager()
        system_data = db_manager.load_system_data()
        
        if system_data.empty:
            return "未知城市"
        
        # 查找匹配的号码段
        prefix = str(phone)[:7]
        
        # 适配不同的列名
        segment_column = '号段'
        city_column = '城市' if '城市' in system_data.columns else 'city'
        
        # 查找匹配的记录
        matching_records = system_data[system_data[segment_column].astype(str).str.startswith(prefix)]
        
        if not matching_records.empty:
            # 返回第一个匹配的城市
            return str(matching_records.iloc[0][city_column])
        else:
            return "未知城市"

class DatabaseManager:
    """数据库管理器"""
    
    def __init__(self):
        # 使用相对路径，确保程序能从外部访问数据库文件
        self.system_sqlite_path = "system_phones.db"  # SQLite数据库路径
        self.user_db_path = "user_phones.db"
        self.init_user_database()
        self.init_system_database()  # 初始化系统数据库
    
    def init_system_database(self):
        """初始化系统号码段数据库"""
        conn = sqlite3.connect(self.system_sqlite_path)
        cursor = conn.cursor()
        
        # 创建系统数据表
        cursor.execute('''
            CREATE TABLE IF NOT EXISTS phone_segments (
                id INTEGER PRIMARY KEY AUTOINCREMENT,
                code TEXT,
                segment TEXT,
                province TEXT,
                city TEXT,
                operator TEXT,
                area_code TEXT,
                zip_code TEXT,
                region_code TEXT
            )
        ''')
        
        # 创建索引以提高查询性能
        cursor.execute('CREATE INDEX IF NOT EXISTS idx_segment ON phone_segments(segment)')
        cursor.execute('CREATE INDEX IF NOT EXISTS idx_area_code ON phone_segments(area_code)')
        cursor.execute('CREATE INDEX IF NOT EXISTS idx_city ON phone_segments(city)')
        
        conn.commit()
        conn.close()
    
    def get_generated_phones(self):
        """获取所有生成的手机号码"""
        conn = sqlite3.connect(self.user_db_path)
        cursor = conn.cursor()
        cursor.execute("SELECT phone_number FROM generated_numbers ORDER BY id")
        phones = [row[0] for row in cursor.fetchall()]
        conn.close()
        return phones
    
    def get_imported_phones(self):
        """获取所有导入的手机号码"""
        conn = sqlite3.connect(self.user_db_path)
        cursor = conn.cursor()
        cursor.execute("SELECT phone_number FROM phone_numbers ORDER BY id")
        phones = [row[0] for row in cursor.fetchall()]
        conn.close()
        return phones
    
    def get_all_phones(self):
        """获取所有手机号码（生成和导入的）"""
        conn = sqlite3.connect(self.user_db_path)
        cursor = conn.cursor()
        cursor.execute("SELECT phone_number FROM generated_numbers ORDER BY id")
        generated_phones = [row[0] for row in cursor.fetchall()]
        cursor.execute("SELECT phone_number FROM phone_numbers ORDER BY id")
        imported_phones = [row[0] for row in cursor.fetchall()]
        conn.close()
        # 合并所有号码
        return generated_phones + imported_phones
        print("SQLite数据库导入完成，性能已优化")
    
    # load_csv_data方法已删除，不再需要CSV文件
    
    def init_user_database(self):
        """初始化用户数据库并迁移表结构以允许重复号码"""
        conn = sqlite3.connect(self.user_db_path)
        cursor = conn.cursor()
        
        # 检查并迁移phone_numbers表结构
        self._migrate_table_structure(conn, 'phone_numbers')
        # 检查并迁移generated_numbers表结构
        self._migrate_table_structure(conn, 'generated_numbers')
        cursor.execute('''
            CREATE TABLE IF NOT EXISTS phone_numbers (
                id INTEGER PRIMARY KEY AUTOINCREMENT,
                phone_number TEXT,
                operator TEXT,
                city TEXT,
                import_time DATETIME DEFAULT CURRENT_TIMESTAMP,
                source_file TEXT
            )
        ''')
        cursor.execute('''
            CREATE TABLE IF NOT EXISTS generated_numbers (
                id INTEGER PRIMARY KEY AUTOINCREMENT,
                phone_number TEXT,
                operator TEXT,
                city TEXT,
                generate_time DATETIME DEFAULT CURRENT_TIMESTAMP,
                rule_used TEXT
            )
        ''')
        conn.commit()
        conn.close()
    
    def _migrate_table_structure(self, conn, table_name):
        """迁移表结构，移除phone_number字段的UNIQUE约束"""
        cursor = conn.cursor()
        
        # 检查表是否存在且phone_number字段是否有UNIQUE约束
        cursor.execute(f"PRAGMA table_info({table_name})")
        columns = cursor.fetchall()
        
        # 检查是否存在UNIQUE约束
        has_unique_constraint = False
        for column in columns:
            if column[1] == 'phone_number' and 'UNIQUE' in str(column):
                has_unique_constraint = True
                break
        
        # 如果有UNIQUE约束，则迁移表结构
        if has_unique_constraint:
            print(f"检测到{table_name}表存在UNIQUE约束，正在迁移表结构...")
            
            # 创建临时表
            temp_table = f"{table_name}_temp"
            cursor.execute(f"DROP TABLE IF EXISTS {temp_table}")
            
            # 创建没有UNIQUE约束的新表
            if table_name == 'phone_numbers':
                cursor.execute('''
                    CREATE TABLE phone_numbers_temp (
                        id INTEGER PRIMARY KEY AUTOINCREMENT,
                        phone_number TEXT,
                        operator TEXT,
                        city TEXT,
                        import_time DATETIME DEFAULT CURRENT_TIMESTAMP,
                        source_file TEXT
                    )
                ''')
            elif table_name == 'generated_numbers':
                cursor.execute('''
                    CREATE TABLE generated_numbers_temp (
                        id INTEGER PRIMARY KEY AUTOINCREMENT,
                        phone_number TEXT,
                        operator TEXT,
                        city TEXT,
                        generate_time DATETIME DEFAULT CURRENT_TIMESTAMP,
                        rule_used TEXT
                    )
                ''')
            
            # 复制数据到临时表
            cursor.execute(f"INSERT INTO {temp_table} SELECT * FROM {table_name}")
            
            # 删除旧表
            cursor.execute(f"DROP TABLE {table_name}")
            
            # 重命名临时表
            cursor.execute(f"ALTER TABLE {temp_table} RENAME TO {table_name}")
            
            print(f"{table_name}表结构迁移完成，已移除UNIQUE约束")
    
    def load_system_data(self):
        """加载系统号码段数据（优先使用SQLite）"""
        # 优先使用SQLite数据库
        if os.path.exists(self.system_sqlite_path):
            try:
                # 使用SQLite查询
                conn = sqlite3.connect(self.system_sqlite_path)
                query = "SELECT * FROM phone_segments"
                df = pd.read_sql_query(query, conn)
                conn.close()
                
                if not df.empty:
                    # 重命名列以保持兼容性
                    df.columns = ['id', '代码', '号段', '省区', '城市', '服务商', '区号', '邮编', '区划代码']
                    return df
            except Exception as e:
                print(f"SQLite数据库查询失败: {e}")
        
        # 如果SQLite不可用，回退到CSV
        print("使用CSV数据源（性能较慢）")
        return self.load_csv_data()
    
    def save_user_phones(self, phones, source_file=""):
        """保存用户导入的手机号码（批量优化版，支持多文件累积导入）"""
        print(f"开始处理来自{source_file}的号码，原始号码数量: {len(phones)}")
        
        # 创建新的数据库连接
        conn = sqlite3.connect(self.user_db_path)
        cursor = conn.cursor()
        
        # 获取导入前的记录数
        cursor.execute("SELECT COUNT(*) FROM phone_numbers")
        before_count = cursor.fetchone()[0]
        print(f"导入前数据库记录数: {before_count}")
        
        valid_count = 0
        invalid_phones = []
        batch_data = []
        all_valid_phones = []  # 保存所有有效号码（包括重复的）
        
        # 先验证所有号码，收集有效号码
        for phone in phones:
            if PhoneValidator.is_valid_phone(phone):
                phone_str = str(phone)
                operator = PhoneValidator.get_operator(phone_str)
                batch_data.append((phone_str, operator, source_file))
                all_valid_phones.append(phone_str)
                valid_count += 1
            else:
                invalid_phones.append(phone)
        
        print(f"验证完成: 有效号码{valid_count}个, 无效号码{len(invalid_phones)}个")
        
        # 使用事务和批量插入提高性能
        if batch_data:
            try:
                # 使用executemany进行批量插入，并添加OR IGNORE来避免UNIQUE约束错误
                cursor.executemany('''
                    INSERT OR IGNORE INTO phone_numbers 
                    (phone_number, operator, source_file) 
                    VALUES (?, ?, ?)
                ''', batch_data)
                conn.commit()
                
                # 获取导入后的记录数
                cursor.execute("SELECT COUNT(*) FROM phone_numbers")
                after_count = cursor.fetchone()[0]
                new_records = after_count - before_count
                print(f"从{source_file}保存: 有效号码{valid_count}个, 新增记录{new_records}条, 数据库总数{after_count}条")
                
                # 验证数据是否正确保存
                cursor.execute("SELECT COUNT(*) FROM phone_numbers WHERE source_file = ?", (source_file,))
                source_count = cursor.fetchone()[0]
                print(f"数据库中来自{source_file}的记录数: {source_count}")
                
            except Exception as e:
                print(f"批量插入数据时出错: {e}")
                conn.rollback()
        
        # 确保连接关闭
        conn.close()
        print(f"数据库连接已关闭")
        return valid_count, invalid_phones, all_valid_phones
    
    def save_generated_phones(self, phones, rule_used=""):
        """保存生成的手机号码"""
        conn = sqlite3.connect(self.user_db_path)
        cursor = conn.cursor()
        
        # 清空generated_numbers表中的旧记录
        cursor.execute("DELETE FROM generated_numbers")
        
        for phone in phones:
            operator = PhoneValidator.get_operator(phone)
            cursor.execute('''
                INSERT OR IGNORE INTO generated_numbers 
                (phone_number, operator, rule_used) 
                VALUES (?, ?, ?)
            ''', (str(phone), operator, rule_used))
        
        conn.commit()
        conn.close()

class ProgressDialog(QDialog):
    """进度弹窗类"""
    
    def __init__(self, parent=None, title="处理中..."):
        super().__init__(parent)
        self.setWindowTitle(title)
        self.setModal(True)  # 模态对话框
        self.setFixedSize(300, 120)
        
        # 创建布局
        layout = QVBoxLayout()
        
        # 进度标签
        self.progress_label = QLabel("正在处理，请稍候...")
        layout.addWidget(self.progress_label)
        
        # 进度条
        self.progress_bar = QProgressBar()
        self.progress_bar.setRange(0, 100)
        self.progress_bar.setValue(0)
        layout.addWidget(self.progress_bar)
        
        # 取消按钮
        self.cancel_btn = QPushButton("取消")
        self.cancel_btn.clicked.connect(self.reject)
        layout.addWidget(self.cancel_btn)
        
        self.setLayout(layout)
    
    def update_progress(self, value, text=None):
        """更新进度"""
        self.progress_bar.setValue(value)
        if text:
            self.progress_label.setText(text)

class PhoneGeneratorThread(QThread):
    """手机号码生成线程"""
    progress_updated = pyqtSignal(int)
    generation_finished = pyqtSignal(list)
    generation_error = pyqtSignal(str)
    
    def __init__(self, rules, count):
        super().__init__()
        self.rules = rules
        self.count = count
        self.db_manager = DatabaseManager()
        # 初始化数据库表，用于存储带序号的生成号码
        self._init_generated_sequence_table()
    
    def _init_generated_sequence_table(self):
        """初始化带序号的生成号码表"""
        try:
            conn = sqlite3.connect(self.db_manager.user_db_path)
            cursor = conn.cursor()
            cursor.execute('''
                CREATE TABLE IF NOT EXISTS generated_sequence_numbers (
                    id INTEGER PRIMARY KEY AUTOINCREMENT,
                    sequence_number INTEGER,
                    phone_number TEXT UNIQUE,
                    operator TEXT,
                    rule_used TEXT,
                    generate_time DATETIME DEFAULT CURRENT_TIMESTAMP
                )
            ''')
            cursor.execute('CREATE INDEX IF NOT EXISTS idx_sequence_number ON generated_sequence_numbers(sequence_number)')
            conn.commit()
            conn.close()
        except Exception as e:
            print(f"初始化序列表失败: {e}")
    
    def run(self):
        # 清空之前的生成记录和用户数据库
        self._clear_generated_sequence()
        self._clear_user_database()
        
        generated_phones = []
        system_data = self.db_manager.load_system_data()
        
        if system_data.empty:
            self.generation_finished.emit([])
            return
        
        # 获取生成规则
        manual_prefix = self.rules.get('manual_prefix')
        area_code = self.rules.get('area_code', '')
        city = self.rules.get('city', '')
        operator = self.rules.get('operator', '')
        required_digits = self.rules.get('required_digits', '')
        exclude_digits = self.rules.get('exclude_digits', '')
        rule_type = self.rules.get('rule_type', '随机')
        
        # 处理"所有区号"选项
        if area_code == "所有区号":
            area_code = ""
        
        # 优先根据运营商筛选号码段
        target_segments = []
        if operator:
            target_segments = self.get_segments_by_operator(operator, system_data)
            # 添加日志，查看获取到的号码段数量
            print(f"找到运营商'{operator}'的号码段数量: {len(target_segments)}")
            if not target_segments:
                self.generation_error.emit(f"未找到运营商 '{operator}' 对应的号码段")
                self.generation_finished.emit([])
                return
            # 如果号码段数量较少，增加一些常用的中国移动号码段作为补充
            if operator == "中国移动" and len(target_segments) < 10:
                # 添加更多常见的中国移动号码段，特别是159开头的
                common_cmcc_segments = ['1340', '1341', '1342', '1343', '1344', '1345', '1346', '1347', '1348', '1350', 
                                      '1351', '1352', '1353', '1354', '1355', '1356', '1357', '1358', '1359', '1360',
                                      '1361', '1362', '1363', '1364', '1365', '1366', '1367', '1368', '1369', '1370',
                                      '1590', '1591', '1592', '1593', '1594', '1595', '1596', '1597', '1598', '1599']
                # 确保不重复添加
                existing_prefixes = {str(s)[:4] for s in target_segments}
                for seg in common_cmcc_segments:
                    if seg not in existing_prefixes:
                        # 将完整的11位号码段格式添加到列表中（假设后7位为0）
                        target_segments.append(seg + '0000000')
                # 随机打乱以增加多样性
                np.random.shuffle(target_segments)
        
        # 如果没有根据运营商筛选或未找到，再根据区号筛选
        if area_code and not target_segments:
            target_segments = self.get_segments_by_area_code(area_code, system_data)
            if not target_segments:
                self.generation_error.emit(f"未找到区号 '{area_code}' 对应的号码段")
                self.generation_finished.emit([])
                return
        
        # 如果指定了城市，先获取该城市的所有号码段
        if city and not target_segments:
            target_segments = self.get_segments_by_city(city, system_data)
            if not target_segments:
                self.generation_error.emit(f"未找到城市 '{city}' 对应的号码段")
                self.generation_finished.emit([])
                return
        
        # 根据规则生成号码
        generated_count = 0
        max_attempts = self.count * 1000  # 最大化尝试次数以确保生成足够数量
        
        # 优化：使用预加载的号码段进行生成
        segment_index = 0
        segment_attempts = 0
        
        # 为每个号码段设置生成计数器，实现负载均衡
        segment_counters = {segment: 0 for segment in target_segments} if target_segments else {}
        
        # 初始随机打乱号码段顺序，确保不总是从第一个开始
        if target_segments:
            np.random.shuffle(target_segments)
        
        # 针对连号规则的特殊处理，按0-9顺序生成
        consecutive_digits = list(range(10))  # 0-9数字列表
        np.random.shuffle(consecutive_digits)  # 随机打乱顺序
        current_digit_index = 0
        
        while generated_count < self.count and max_attempts > 0:
            if self.isInterruptionRequested():
                break
                
            # 使用手工输入的前缀
            prefix = manual_prefix
            
            # 特殊处理：如果有手工输入的前缀并且是连号规则
            if prefix and rule_type in ["七连号", "六连号", "五连号", "四连号"]:
                # 为手工前缀生成对应的连号，尝试多种可能的位置
                if rule_type == "七连号":
                    phone = self.generate_manual_prefix_7_consecutive(prefix)
                elif rule_type == "六连号":
                    phone = self.generate_manual_prefix_6_consecutive(prefix)
                elif rule_type == "五连号":
                    phone = self.generate_manual_prefix_5_consecutive(prefix)
                elif rule_type == "四连号":
                    phone = self.generate_manual_prefix_4_consecutive(prefix)
                suffix = ""
            else:
                # 如果没有手工输入前缀或不是七连号规则，正常生成前缀
                if not prefix:
                    # 如果有目标号码段，从号码段中获取前缀
                    if target_segments:
                        # 改进的负载均衡：随机选择一个号码段，但倾向于选择生成数量较少的
                        if generated_count % 5 == 0:  # 每生成5个号码，重新排序号码段
                            # 按生成数量排序，然后随机微调顺序，避免总是选择同一个
                            sorted_segments = sorted(target_segments, key=lambda x: segment_counters[x])
                            # 对前半部分随机打乱，保持总体优先顺序但增加随机性
                            mid = max(1, len(sorted_segments) // 2)
                            top_half = sorted_segments[:mid]
                            np.random.shuffle(top_half)
                            target_segments = top_half + sorted_segments[mid:]
                        
                        # 选择当前优先的号码段
                        current_segment = target_segments[0]
                        
                        # 从号码段中获取前4位作为基础前缀
                        base_prefix = str(current_segment)[:4]  # 获取前4位
                        
                        # 针对连号规则的特殊处理
                        if rule_type in ["七连号", "六连号", "五连号", "四连号"]:
                            # 获取连号需要的相同数字（按顺序使用0-9）
                            consecutive_digit = str(consecutive_digits[current_digit_index % 10])
                            current_digit_index += 1
                            
                            # 根据连号类型构造完整前缀
                            if rule_type == "七连号":
                                # 七连号最简单构造法：前缀3位 + 7个连号数字
                                prefix = base_prefix[:3] + consecutive_digit * 7
                            elif rule_type == "六连号":
                                # 六连号：前缀5位 + 2个连号数字
                                prefix = base_prefix + str(np.random.randint(0, 10)) + consecutive_digit * 2
                            elif rule_type == "五连号":
                                # 五连号：前缀6位 + 1个连号数字
                                prefix = base_prefix + ''.join(str(np.random.randint(0, 10)) for _ in range(2)) + consecutive_digit
                            elif rule_type == "四连号":
                                # 四连号：前缀7位，后缀4位相同
                                prefix = base_prefix + ''.join(str(np.random.randint(0, 10)) for _ in range(3))
                        else:
                            # 非连号规则，正常生成前缀
                            prefix = base_prefix + ''.join(str(np.random.randint(0, 10)) for _ in range(3))
                        
                        segment_attempts += 1
                        
                        # 如果当前号码段尝试次数过多，强制切换到下一个号码段
                        if segment_attempts > 30 and len(target_segments) > 1:
                            # 轮换到下一个号码段
                            target_segments = target_segments[1:] + [target_segments[0]]
                            segment_attempts = 0
                    else:
                        # 生成1开头的3位前缀（手机号前3位）
                        first_digit = '1'
                        second_digit = str(np.random.randint(3, 10))  # 3-9
                        third_digit = str(np.random.randint(0, 10))
                        prefix = first_digit + second_digit + third_digit
                
                # 根据规则类型生成后缀
                if rule_type in ["七连号", "六连号", "五连号", "四连号"]:
                    if rule_type == "七连号":
                        # 七连号特殊处理：前缀已经包含7个连号数字，只需要补充剩余1位
                        # 确保总长度为11位
                        needed_length = 11 - len(prefix)
                        if needed_length > 0:
                            # 使用单个随机数字补充，确保格式正确
                            suffix = str(np.random.randint(0, 10)) if needed_length == 1 else ''.join(str(np.random.randint(0, 10)) for _ in range(needed_length))
                        else:
                            suffix = ''
                    else:
                        # 其他连号规则
                        # 从前缀中提取最后1位作为连号数字
                        consecutive_digit = prefix[-1]  # 前缀最后一位应该是连号数字
                        suffix = consecutive_digit * 4
                else:
                    # 其他规则的正常处理
                    # 补全到7位
                    if len(prefix) < 7:
                        prefix = prefix + '0' * (7 - len(prefix))
                    elif len(prefix) > 7:
                        prefix = prefix[:7]
                    
                    # 根据规则类型生成后缀
                    suffix = self.generate_suffix_by_rule(rule_type)
                
                # 生成完整号码
                phone = prefix + suffix
            
            # 验证连号规则
            if rule_type in ["七连号", "六连号", "五连号", "四连号"]:
                # 使用专门的验证方法检查连号
                is_valid = False
                if rule_type == "七连号":
                    is_valid = self._is_valid_7_consecutive(phone)
                    # 如果检查失败，直接修正为有效的七连号
                    if not is_valid:
                        # 确保phone是字符串类型
                        if isinstance(phone, list):
                            phone = ''.join(phone)
                        
                        # 优先保持用户指定的前缀
                        if manual_prefix:
                            # 提取用户前缀（清理后的数字部分）
                            clean_prefix = ''.join(filter(str.isdigit, manual_prefix))[:11]
                            if clean_prefix and len(clean_prefix) <= 11:
                                # 生成七连号：确保总长度为11位
                                remaining_length = 11 - len(clean_prefix)
                                if remaining_length >= 7:
                                    # 如果前缀足够短，可以在后缀中放七连号
                                    consecutive_digit = str(np.random.randint(0, 10))
                                    seven_consecutive = consecutive_digit * 7
                                    extra_digits = ''.join(str(np.random.randint(0, 10)) for _ in range(remaining_length - 7))
                                    phone = clean_prefix + seven_consecutive + extra_digits
                                else:
                                    # 如果前缀太长，就在整个号码中找位置放七连号
                                    # 这里简化处理，直接在开头放前缀，后面放随机数字
                                    phone = clean_prefix + ''.join(str(np.random.randint(0, 10)) for _ in range(remaining_length))
                        else:
                            # 如果没有用户指定前缀，使用原来的逻辑
                            middle_digit = str(np.random.randint(0, 10))
                            last_digit = str(np.random.randint(0, 10))
                            phone = phone[:3] + middle_digit * 7 + last_digit
                elif rule_type == "六连号":
                    is_valid = self._is_valid_6_consecutive(phone)
                    if not is_valid:
                        max_attempts -= 1
                        continue
                elif rule_type == "五连号":
                    is_valid = self._is_valid_5_consecutive(phone)
                    if not is_valid:
                        max_attempts -= 1
                        continue
                elif rule_type == "四连号":
                    is_valid = self._is_valid_4_consecutive(phone)
                    if not is_valid:
                        max_attempts -= 1
                        continue
            
            # 对于七连号，完全移除所有限制条件
            if rule_type == "七连号":
                # 七连号条件本身已经非常严格，移除所有其他限制以确保能生成足够数量
                # 直接跳过所有额外检查
                pass
            else:
                # 常规规则下的必需数字检查
                if required_digits:
                    if required_digits not in phone:
                        max_attempts -= 1
                        continue  # 跳过不包含必需数字的号码
                
                # 常规规则下的排除数字检查
                if exclude_digits:
                    if any(digit in phone for digit in exclude_digits):
                        max_attempts -= 1
                        continue  # 跳过包含排除数字的号码
            
            # 检查号码是否重复
            if phone in generated_phones:
                max_attempts -= 1
                continue
            
            # 验证号码有效性
            if PhoneValidator.is_valid_phone(phone):
                # 优化：如果已经通过号码段过滤，跳过区号检查
                if not target_segments and area_code:
                    # 根据号码前缀查找对应的区号
                    prefix = str(phone)[:7]
                    phone_area_code = self.get_area_code_by_prefix(prefix, system_data)
                    if phone_area_code != area_code:
                        max_attempts -= 1
                        continue  # 跳过不匹配区号的号码
                
                # 优化：如果已经通过号码段过滤，跳过城市检查
                if not target_segments and city:
                    phone_city = PhoneValidator.get_city(phone)
                    if phone_city != city:
                        max_attempts -= 1
                        continue  # 跳过不匹配城市的号码
                
                # 检查运营商是否匹配（如果指定了）
                if operator:
                    phone_operator = PhoneValidator.get_operator(phone)
                    if operator not in phone_operator:
                        max_attempts -= 1
                        continue
                
                # 获取运营商信息
                phone_operator = PhoneValidator.get_operator(phone)
                
                # 保存到数据库，添加序号
                self._save_phone_with_sequence(phone, generated_count + 1, phone_operator, rule_type)
                
                generated_phones.append(phone)
                generated_count += 1
                
                # 成功生成后更新计数器
                if target_segments and 'current_segment' in locals():
                    segment_counters[current_segment] += 1
                    
                    # 每生成10个号码，重新平衡号码段选择
                    if generated_count % 10 == 0:
                        # 重新排序号码段，让生成数量少的优先
                        target_segments.sort(key=lambda x: segment_counters[x])
                        segment_attempts = 0
                
                # 每生成20个号码更新一次进度并短暂暂停，避免UI更新过于频繁
                if generated_count % 20 == 0:
                    # 发出进度更新信号
                    self.progress_updated.emit(int(generated_count / self.count * 100))
                    # 短暂暂停，让UI有时间响应
                    self.msleep(10)
            
            max_attempts -= 1
            
            # 只在生成数量为10的倍数时更新进度，避免进度更新过于频繁
            if generated_count % 10 == 0:
                progress = int((generated_count / self.count) * 100)
                self.progress_updated.emit(progress)
        
        # 检查连号生成失败情况
        if generated_count < self.count:
            warning_msg = f"警告: 只生成了 {generated_count} 个有效号码，目标 {self.count} 个"
            
            # 如果是连号规则且生成数量不足，给出具体提示
            if rule_type in ["七连号", "六连号", "五连号", "四连号", "三连号"]:
                if required_digits:
                    warning_msg += f"\n提示: 由于设置了必需数字 '{required_digits}'，无法生成足够的{rule_type}，建议减少限制条件"
                elif exclude_digits:
                    warning_msg += f"\n提示: 由于设置了排除数字 '{exclude_digits}'，无法生成足够的{rule_type}，建议减少限制条件"
                elif area_code:
                    warning_msg += f"\n提示: 由于设置了区号 '{area_code}'，无法生成足够的{rule_type}，建议减少限制条件"
                elif city:
                    warning_msg += f"\n提示: 由于设置了城市 '{city}'，无法生成足够的{rule_type}，建议减少限制条件"
                else:
                    warning_msg += f"\n提示: 无法生成足够的{rule_type}，建议减少其他限制条件"
            
            self.generation_error.emit(warning_msg)
            print(warning_msg)
        
        # 生成完成，确保所有数据都已提交到数据库
        try:
            # 确保关闭类变量中的数据库连接
            if hasattr(self, '_db_connection') and self._db_connection:
                self._db_connection.commit()  # 提交剩余的数据
                self._db_connection.close()
                self._db_connection = None
            else:
                # 如果没有活动连接，创建一个新连接进行最终提交
                conn = sqlite3.connect(self.db_manager.user_db_path)
                conn.commit()
                conn.close()
            print(f"生成完成，成功提交所有{generated_count}个号码到数据库")
        except Exception as e:
            print(f"最终提交数据库失败: {e}")
        finally:
            # 确保连接已关闭
            if hasattr(self, '_db_connection'):
                try:
                    if self._db_connection:
                        self._db_connection.close()
                except:
                    pass
                self._db_connection = None
        
        # 发出完成信号
        self.generation_finished.emit(generated_phones)
    
    def _clear_generated_sequence(self):
        """清空之前的生成记录"""
        try:
            conn = sqlite3.connect(self.db_manager.user_db_path)
            cursor = conn.cursor()
            cursor.execute("DELETE FROM generated_sequence_numbers")
            conn.commit()
            conn.close()
        except Exception as e:
            print(f"清空序列表失败: {e}")
    
    def _clear_user_database(self):
        """清空用户数据库中的所有表"""
        try:
            conn = sqlite3.connect(self.db_manager.user_db_path)
            cursor = conn.cursor()
            # 清空所有用户相关表
            cursor.execute("DELETE FROM generated_numbers")
            cursor.execute("DELETE FROM phone_numbers")
            cursor.execute("DELETE FROM generated_sequence_numbers")
            conn.commit()
            conn.close()
            print("用户数据库已清空")
        except Exception as e:
            print(f"清空用户数据库失败: {e}")
    
    def _save_phone_with_sequence(self, phone, sequence_number, operator, rule_used):
        """保存带序号的号码到数据库"""
        try:
            # 使用类变量管理数据库连接，避免频繁打开关闭连接
            if not hasattr(self, '_db_connection') or self._db_connection is None:
                self._db_connection = sqlite3.connect(self.db_manager.user_db_path)
                
            cursor = self._db_connection.cursor()
            cursor.execute('''
                INSERT OR IGNORE INTO generated_sequence_numbers 
                (sequence_number, phone_number, operator, rule_used) 
                VALUES (?, ?, ?, ?)
            ''', (sequence_number, phone, operator, rule_used))
            
            # 批量提交，减少数据库操作次数
            if sequence_number % 20 == 0:
                self._db_connection.commit()
                print(f"已提交批次 {sequence_number//20}")
                # 短暂让出资源，避免线程阻塞
                self.msleep(1)
                
            # 只在特定条件下关闭连接，通常应该在完成时统一关闭
            if sequence_number % 100 == 0:
                self._db_connection.close()
                self._db_connection = None
        except Exception as e:
            print(f"保存带序号的号码失败: {e}")
            # 发生错误时尝试关闭连接
            try:
                if hasattr(self, '_db_connection') and self._db_connection:
                    self._db_connection.close()
                    self._db_connection = None
            except:
                pass
    
    def has_consecutive_digits(self, phone, count):
        """检查手机号中是否有指定数量的连续相同数字"""
        phone_str = str(phone)
        # 优化检查算法，提高效率
        current_char = None
        current_streak = 0
        
        for char in phone_str:
            if char == current_char:
                current_streak += 1
                if current_streak >= count:
                    return True
            else:
                current_char = char
                current_streak = 1
        
        return False
    
    def has_consecutive_digits_at_position(self, phone, count, start_index):
        """检查手机号中从指定位置开始的连续相同数字"""
        phone_str = str(phone)
        if start_index + count > len(phone_str):
            return False
        
        # 检查从start_index开始的count个数字是否全部相同
        digits = phone_str[start_index:start_index + count]
        return len(set(digits)) == 1
    
    def generate_manual_prefix_7_consecutive(self, prefix):
        """生成指定前缀的七连号手机号码。
        严格按照用户UI中填写的前缀生成，确保号码前几位与用户输入完全一致。
        
        Args:
            prefix: 用户在UI中输入的前缀
            
        Returns:
            str: 生成的11位七连号手机号码
        """
        # 确保前缀是字符串类型并去除空白字符
        prefix = str(prefix).strip()
        
        # 确保前缀是纯数字并获取clean_prefix
        if prefix:
            # 只保留数字字符
            clean_prefix = ''.join(filter(str.isdigit, prefix))
            # 如果过滤后没有数字，使用默认值
            if not clean_prefix:
                clean_prefix = "1591"
        else:
            # 如果没有前缀，使用默认的4位前缀
            clean_prefix = "1591"
        
        # 确保前缀长度至少为1位，最多11位
        clean_prefix = clean_prefix[:11]  # 截断过长的前缀
        if not clean_prefix:
            clean_prefix = "1591"
        
        # 计算剩余需要生成的位数
        remaining_length = 11 - len(clean_prefix)
        
        # 确保至少有足够的位数生成七连号
        if remaining_length < 7:
            # 如果前缀太长，无法在后缀中生成七连号
            # 我们可以在整个11位号码中寻找可能的七连号位置
            # 但这里简化处理，直接生成一个合理的号码
            return clean_prefix + ''.join(str(np.random.randint(0, 10)) for _ in range(remaining_length))
        
        # 生成七连号：生成一个0-9之间的随机数字，重复7次
        consecutive_digit = str(np.random.randint(0, 10))
        seven_consecutive = consecutive_digit * 7
        
        # 计算还需要补充的随机位数
        extra_digits_needed = remaining_length - 7
        
        # 生成额外的随机数字
        extra_digits = ''.join(str(np.random.randint(0, 10)) for _ in range(extra_digits_needed))
        
        # 构建完整号码：前缀 + 七连号 + 额外随机数字
        phone = clean_prefix + seven_consecutive + extra_digits
        
        # 确保长度为11位
        phone = phone[:11]
        
        # 初始化或更新数据结构（保持原有逻辑的兼容性）
        if not hasattr(self, '_7consecutive_data'):
            self._7consecutive_data = {}
        
        return phone
        
        # 转换为列表
        combinations_list = list(all_combinations)
        
        # 初始化或更新数据结构
        if not hasattr(self, '_7consecutive_data'):
            self._7consecutive_data = {}
        
        if prefix not in self._7consecutive_data or not self._7consecutive_data[prefix].get('all_combinations'):
            # 随机打乱顺序
            np.random.shuffle(combinations_list)
            # 保存组合
            self._7consecutive_data[prefix] = {
                'all_combinations': combinations_list,
                'counter': 0
            }
        
        # 循环使用当前前缀的所有组合
        prefix_data = self._7consecutive_data[prefix]
        total_combinations = len(prefix_data['all_combinations'])
        current_index = prefix_data['counter'] % total_combinations
        number = prefix_data['all_combinations'][current_index]
        
        # 更新计数器
        prefix_data['counter'] += 1
        
        return number
    
    def _is_valid_7_consecutive(self, number):
        """
        验证号码是否符合七连号规则
        
        Args:
            number: 待验证的号码字符串
            
        Returns:
            是否符合七连号规则
        """
        # 验证模式1: d4-d10相同
        pattern1_valid = False
        if len(number) >= 12:
            test_digit = number[3]
            pattern1_valid = all(number[i] == test_digit for i in range(3, 10))
        
        # 验证模式2: d5-d11相同
        pattern2_valid = False
        if len(number) >= 12:
            test_digit = number[4]
            pattern2_valid = all(number[i] == test_digit for i in range(4, 11))
        
        return pattern1_valid or pattern2_valid
    
    def _is_valid_6_consecutive(self, number):
        """
        验证号码是否符合六连号规则
        
        Args:
            number: 待验证的号码字符串
            
        Returns:
            是否符合六连号规则
        """
        # 验证模式1: d4-d9相同
        pattern1_valid = False
        if len(number) >= 11:
            test_digit = number[3]
            pattern1_valid = all(number[i] == test_digit for i in range(3, 9))
        
        # 验证模式2: d5-d10相同
        pattern2_valid = False
        if len(number) >= 11:
            test_digit = number[4]
            pattern2_valid = all(number[i] == test_digit for i in range(4, 10))
        
        # 验证模式3: d6-d11相同
        pattern3_valid = False
        if len(number) >= 11:
            test_digit = number[5]
            pattern3_valid = all(number[i] == test_digit for i in range(5, 11))
        
        return pattern1_valid or pattern2_valid or pattern3_valid
    
    def _is_valid_5_consecutive(self, number):
        """
        验证号码是否符合五连号规则
        
        Args:
            number: 待验证的号码字符串
            
        Returns:
            是否符合五连号规则
        """
        # 验证多个可能的位置
        positions = [
            (3, 8),  # d4-d8
            (4, 9),  # d5-d9
            (5, 10), # d6-d10
            (6, 11)  # d7-d11
        ]
        
        for start, end in positions:
            if len(number) >= end:
                test_digit = number[start]
                if all(number[i] == test_digit for i in range(start, end)):
                    return True
        
        return False
    
    def _is_valid_4_consecutive(self, number):
        """
        验证号码是否符合四连号规则
        
        Args:
            number: 待验证的号码字符串
            
        Returns:
            是否符合四连号规则
        """
        # 验证多个可能的位置
        positions = [
            (3, 7),  # d4-d7
            (4, 8),  # d5-d8
            (5, 9),  # d6-d9
            (6, 10), # d7-d10
            (7, 11)  # d8-d11
        ]
        
        for start, end in positions:
            if len(number) >= end:
                test_digit = number[start]
                if all(number[i] == test_digit for i in range(start, end)):
                    return True
        
        return False
    
    def generate_manual_prefix_6_consecutive(self, prefix):
        """
        生成指定前缀的所有六连号手机号码。
        六连号可能出现在三个位置：
        1. 第4位到第9位（d4-d9相同）
        2. 第5位到第10位（d5-d10相同）
        3. 第6位到第11位（d6-d11相同）
        通过集合自动去重重叠部分。
        
        前缀处理：
        - 对于3位前缀（如159）：生成全部可能的组合
        - 对于4位前缀（如1591）：固定第4位，生成相应数量的组合
        """
        # 确保前缀是字符串类型
        prefix = str(prefix)
        
        # 使用集合存储所有唯一的六连号组合
        all_combinations = set()
        
        # 区分3位前缀和4位前缀的处理逻辑
        if len(prefix) >= 4:
            # 4位前缀处理（如1591）
            # 固定前4位，根据六连号的位置限制生成组合
            base_prefix = prefix[:3]
            fourth_digit = prefix[3]  # 固定第4位
            
            # 模式1: d4-d9相同，但d4已固定
            # 由于d4固定为fourth_digit，我们只需要检查是否符合条件
            for digit in range(10):
                # 只有当digit等于fourth_digit时，才可能形成d4-d9的六连号
                if digit == fourth_digit:
                    for last_digit in range(10):
                        for last_digit2 in range(10):
                            number = f"{base_prefix}{fourth_digit}{digit}{digit}{digit}{digit}{digit}{digit}{last_digit}{last_digit2}"
                            all_combinations.add((number[:11], 1))  # 标记为模式1
            
            # 模式2: d5-d10相同，d4固定
            # d4已固定为fourth_digit，d5-d10需要相同
            for digit in range(10):
                for last_digit in range(10):
                    number = f"{base_prefix}{fourth_digit}{digit}{digit}{digit}{digit}{digit}{digit}{last_digit}"
                    all_combinations.add((number[:11], 2))  # 标记为模式2
            
            # 模式3: d6-d11相同，d4固定
            # d4已固定为fourth_digit，d5可以随机，d6-d11需要相同
            for second_digit in range(10):
                for digit in range(10):
                    number = f"{base_prefix}{fourth_digit}{second_digit}{digit}{digit}{digit}{digit}{digit}{digit}"
                    all_combinations.add((number[:11], 3))  # 标记为模式3
        else:
            # 3位前缀处理（如159）
            base_prefix = prefix[:3].ljust(3, '0')
            
            # 模式1: 六连号在d4-d9
            for digit in range(10):
                for last_digit in range(10):
                    for last_digit2 in range(10):
                        number = f"{base_prefix}{digit}{digit}{digit}{digit}{digit}{digit}{last_digit}{last_digit2}"
                        all_combinations.add((number[:11], 1))  # 标记为模式1
            
            # 模式2: 六连号在d5-d10
            for first_digit in range(10):
                for digit in range(10):
                    for last_digit in range(10):
                        number = f"{base_prefix}{first_digit}{digit}{digit}{digit}{digit}{digit}{digit}{last_digit}"
                        all_combinations.add((number[:11], 2))  # 标记为模式2
            
            # 模式3: 六连号在d6-d11
            for first_digit in range(10):
                for second_digit in range(10):
                    for digit in range(10):
                        number = f"{base_prefix}{first_digit}{second_digit}{digit}{digit}{digit}{digit}{digit}{digit}"
                        all_combinations.add((number[:11], 3))  # 标记为模式3
            
        # 初始化或更新数据结构
        if not hasattr(self, '_6consecutive_data'):
            self._6consecutive_data = {}
        
        if prefix not in self._6consecutive_data or not self._6consecutive_data[prefix].get('all_combinations'):
            # 转换为列表并打乱顺序
            combinations_list = list(all_combinations)
            np.random.shuffle(combinations_list)
            # 保存组合
            self._6consecutive_data[prefix] = {
                'all_combinations': combinations_list,
                'counter': 0
            }
        
        # 循环使用当前前缀的所有组合
        prefix_data = self._6consecutive_data[prefix]
        total_combinations = len(prefix_data['all_combinations'])
        current_index = prefix_data['counter'] % total_combinations
        number, mode = prefix_data['all_combinations'][current_index]
        
        # 更新计数器
        prefix_data['counter'] += 1
        
        return number
    
    def generate_manual_prefix_5_consecutive(self, prefix):
        """
        生成指定前缀的所有五连号手机号码。
        五连号可能出现在多个位置，支持多种模式。
        
        前缀处理：
        - 对于3位前缀（如159）：生成全部可能的组合
        - 对于4位前缀（如1591）：固定第4位，生成相应数量的组合
        """
        # 确保前缀是字符串类型
        prefix = str(prefix)
        
        # 使用集合存储所有唯一的五连号组合
        all_combinations = set()
        
        # 区分3位前缀和4位前缀的处理逻辑
        if len(prefix) >= 4:
            # 4位前缀处理（如1591）
            # 固定前4位，根据五连号的位置限制生成组合
            base_prefix = prefix[:3]
            fourth_digit = prefix[3]  # 固定第4位
            
            # 生成多种可能的五连号模式
            for start_pos in range(4, 8):  # 开始位置从d4到d7
                for digit in range(10):
                    # 根据不同的开始位置生成不同的组合
                    if start_pos == 4:  # d4-d8
                        # 当d4是连号的一部分时，必须与fourth_digit相同
                        if digit == fourth_digit:
                            for last_digit in range(10):
                                for last_digit2 in range(10):
                                    for last_digit3 in range(10):
                                        number = f"{base_prefix}{fourth_digit}{digit}{digit}{digit}{digit}{digit}{last_digit}{last_digit2}{last_digit3}"
                                        all_combinations.add((number[:11], start_pos))
                    elif start_pos == 5:  # d5-d9
                        for last_digit in range(10):
                            for last_digit2 in range(10):
                                number = f"{base_prefix}{fourth_digit}{digit}{digit}{digit}{digit}{digit}{last_digit}{last_digit2}"
                                all_combinations.add((number[:11], start_pos))
                    elif start_pos == 6:  # d6-d10
                        for second_digit in range(10):
                            for last_digit in range(10):
                                number = f"{base_prefix}{fourth_digit}{second_digit}{digit}{digit}{digit}{digit}{digit}{last_digit}"
                                all_combinations.add((number[:11], start_pos))
                    elif start_pos == 7:  # d7-d11
                        for second_digit in range(10):
                            for third_digit in range(10):
                                number = f"{base_prefix}{fourth_digit}{second_digit}{third_digit}{digit}{digit}{digit}{digit}{digit}"
                                all_combinations.add((number[:11], start_pos))
        else:
            # 3位前缀处理（如159）
            base_prefix = prefix[:3].ljust(3, '0')
            
            # 生成多种可能的五连号模式
            for start_pos in range(4, 8):  # 开始位置从d4到d7
                for digit in range(10):
                    # 根据不同的开始位置生成不同的组合
                    if start_pos == 4:  # d4-d8
                        for last_digit in range(10):
                            for last_digit2 in range(10):
                                for last_digit3 in range(10):
                                    number = f"{base_prefix}{digit}{digit}{digit}{digit}{digit}{last_digit}{last_digit2}{last_digit3}"
                                    all_combinations.add((number[:11], start_pos))
                    elif start_pos == 5:  # d5-d9
                        for first_digit in range(10):
                            for last_digit in range(10):
                                for last_digit2 in range(10):
                                    number = f"{base_prefix}{first_digit}{digit}{digit}{digit}{digit}{digit}{last_digit}{last_digit2}"
                                    all_combinations.add((number[:11], start_pos))
                    elif start_pos == 6:  # d6-d10
                        for first_digit in range(10):
                            for second_digit in range(10):
                                for last_digit in range(10):
                                    number = f"{base_prefix}{first_digit}{second_digit}{digit}{digit}{digit}{digit}{digit}{last_digit}"
                                    all_combinations.add((number[:11], start_pos))
                    elif start_pos == 7:  # d7-d11
                        for first_digit in range(10):
                            for second_digit in range(10):
                                for third_digit in range(10):
                                    number = f"{base_prefix}{first_digit}{second_digit}{third_digit}{digit}{digit}{digit}{digit}{digit}"
                                    all_combinations.add((number[:11], start_pos))
        
        # 初始化或更新数据结构
        if not hasattr(self, '_5consecutive_data'):
            self._5consecutive_data = {}
        
        if prefix not in self._5consecutive_data or not self._5consecutive_data[prefix].get('all_combinations'):
            # 转换为列表并打乱顺序
            combinations_list = list(all_combinations)
            np.random.shuffle(combinations_list)
            # 保存组合
            self._5consecutive_data[prefix] = {
                'all_combinations': combinations_list,
                'counter': 0
            }
        
        # 循环使用当前前缀的所有组合
        prefix_data = self._5consecutive_data[prefix]
        total_combinations = len(prefix_data['all_combinations'])
        current_index = prefix_data['counter'] % total_combinations
        number, mode = prefix_data['all_combinations'][current_index]
        
        # 更新计数器
        prefix_data['counter'] += 1
        
        return number
    
    def generate_manual_prefix_4_consecutive(self, prefix):
        """
        生成指定前缀的所有四连号手机号码。
        四连号可能出现在多个位置，支持多种模式。
        
        前缀处理：
        - 对于3位前缀（如159）：生成全部可能的组合
        - 对于4位前缀（如1591）：固定第4位，生成相应数量的组合
        """
        # 确保前缀是字符串类型
        prefix = str(prefix)
        
        # 使用集合存储所有唯一的四连号组合
        all_combinations = set()
        
        # 区分3位前缀和4位前缀的处理逻辑
        if len(prefix) >= 4:
            # 4位前缀处理（如1591）
            # 固定前4位，根据四连号的位置限制生成组合
            base_prefix = prefix[:3]
            fourth_digit = prefix[3]  # 固定第4位
            
            # 生成多种可能的四连号模式
            for start_pos in range(4, 9):  # 开始位置从d4到d8
                for digit in range(10):
                    # 根据不同的开始位置生成不同的组合
                    if start_pos == 4:  # d4-d7
                        # 当d4是连号的一部分时，必须与fourth_digit相同
                        if digit == fourth_digit:
                            for last_digit in range(10):
                                for last_digit2 in range(10):
                                    for last_digit3 in range(10):
                                        for last_digit4 in range(10):
                                            number = f"{base_prefix}{fourth_digit}{digit}{digit}{digit}{digit}{last_digit}{last_digit2}{last_digit3}{last_digit4}"
                                            all_combinations.add((number[:11], start_pos))
                    elif start_pos == 5:  # d5-d8
                        for last_digit in range(10):
                            for last_digit2 in range(10):
                                for last_digit3 in range(10):
                                    number = f"{base_prefix}{fourth_digit}{digit}{digit}{digit}{digit}{last_digit}{last_digit2}{last_digit3}"
                                    all_combinations.add((number[:11], start_pos))
                    elif start_pos == 6:  # d6-d9
                        for second_digit in range(10):
                            for last_digit in range(10):
                                for last_digit2 in range(10):
                                    number = f"{base_prefix}{fourth_digit}{second_digit}{digit}{digit}{digit}{digit}{last_digit}{last_digit2}"
                                    all_combinations.add((number[:11], start_pos))
                    elif start_pos == 7:  # d7-d10
                        for second_digit in range(10):
                            for third_digit in range(10):
                                for last_digit in range(10):
                                    number = f"{base_prefix}{fourth_digit}{second_digit}{third_digit}{digit}{digit}{digit}{digit}{last_digit}"
                                    all_combinations.add((number[:11], start_pos))
                    elif start_pos == 8:  # d8-d11
                        for second_digit in range(10):
                            for third_digit in range(10):
                                for fourth_digit_pos in range(10):
                                    number = f"{base_prefix}{fourth_digit}{second_digit}{third_digit}{fourth_digit_pos}{digit}{digit}{digit}{digit}"
                                    all_combinations.add((number[:11], start_pos))
        else:
            # 3位前缀处理（如159）
            base_prefix = prefix[:3].ljust(3, '0')
            
            # 生成多种可能的四连号模式
            for start_pos in range(4, 9):  # 开始位置从d4到d8
                for digit in range(10):
                    # 根据不同的开始位置生成不同的组合
                    if start_pos == 4:  # d4-d7
                        for last_digit in range(10):
                            for last_digit2 in range(10):
                                for last_digit3 in range(10):
                                    for last_digit4 in range(10):
                                        number = f"{base_prefix}{digit}{digit}{digit}{digit}{last_digit}{last_digit2}{last_digit3}{last_digit4}"
                                        all_combinations.add((number[:11], start_pos))
                    elif start_pos == 5:  # d5-d8
                        for first_digit in range(10):
                            for last_digit in range(10):
                                for last_digit2 in range(10):
                                    for last_digit3 in range(10):
                                        number = f"{base_prefix}{first_digit}{digit}{digit}{digit}{digit}{last_digit}{last_digit2}{last_digit3}"
                                        all_combinations.add((number[:11], start_pos))
                    elif start_pos == 6:  # d6-d9
                        for first_digit in range(10):
                            for second_digit in range(10):
                                for last_digit in range(10):
                                    for last_digit2 in range(10):
                                        number = f"{base_prefix}{first_digit}{second_digit}{digit}{digit}{digit}{digit}{last_digit}{last_digit2}"
                                        all_combinations.add((number[:11], start_pos))
                    elif start_pos == 7:  # d7-d10
                        for first_digit in range(10):
                            for second_digit in range(10):
                                for third_digit in range(10):
                                    for last_digit in range(10):
                                        number = f"{base_prefix}{first_digit}{second_digit}{third_digit}{digit}{digit}{digit}{digit}{last_digit}"
                                        all_combinations.add((number[:11], start_pos))
                    elif start_pos == 8:  # d8-d11
                        for first_digit in range(10):
                            for second_digit in range(10):
                                for third_digit in range(10):
                                    for fourth_digit in range(10):
                                        number = f"{base_prefix}{first_digit}{second_digit}{third_digit}{fourth_digit}{digit}{digit}{digit}{digit}"
                                        all_combinations.add((number[:11], start_pos))
        
        # 初始化或更新数据结构
        if not hasattr(self, '_4consecutive_data'):
            self._4consecutive_data = {}
        
        if prefix not in self._4consecutive_data or not self._4consecutive_data[prefix].get('all_combinations'):
            # 转换为列表并打乱顺序
            combinations_list = list(all_combinations)
            np.random.shuffle(combinations_list)
            # 保存组合
            self._4consecutive_data[prefix] = {
                'all_combinations': combinations_list,
                'counter': 0
            }
        
        # 循环使用当前前缀的所有组合
        prefix_data = self._4consecutive_data[prefix]
        total_combinations = len(prefix_data['all_combinations'])
        current_index = prefix_data['counter'] % total_combinations
        number, mode = prefix_data['all_combinations'][current_index]
        
        # 更新计数器
        prefix_data['counter'] += 1
        
        return number
    
    def generate_7_consecutive_advanced(self, first_7_digits, pattern="position_5_11"):
        """
        增强版7连号生成，支持不同模式
        :param first_7_digits: 前7位号码
        :param pattern: 连号模式
            - "position_5_11": 第5-11位连号（最常用）
            - "position_4_10": 第4-10位连号
            - "position_1_7": 前7位自身连号检测
        :return: 生成的手机号或None
        """
        
        if pattern == "position_5_11":
            # 第5-7位作为基础，生成后4位相同数字
            base_digit = first_7_digits[4]  # 第5位
            if first_7_digits[4] == first_7_digits[5] == first_7_digits[6]:
                last_4_digits = base_digit * 4
                return first_7_digits + last_4_digits
        
        elif pattern == "position_4_10":
            # 第4-7位作为基础，生成后4位的前3位相同
            base_digit = first_7_digits[3]  # 第4位
            if len(set(first_7_digits[3:7])) == 1:  # 第4-7位都相同
                last_4_digits = base_digit * 4
                return first_7_digits + last_4_digits
        
        elif pattern == "position_1_7":
            # 检查前7位自身是否已经是7连号
            if len(set(first_7_digits)) == 1:
                # 前7位已经是连号，后4位可任意生成
                last_4_digits = first_7_digits[0] * 4
                return first_7_digits + last_4_digits
        
        return None
    
    def generate_all_patterns(self, first_7_digits):
        """生成所有可能的7连号模式"""
        patterns = ["position_5_11", "position_4_10", "position_1_7"]
        results = {}
        
        for pattern in patterns:
            result = self.generate_7_consecutive_advanced(first_7_digits, pattern)
            if result:
                results[pattern] = result
        
        return results
    
    def generate_suffix_by_rule(self, rule_type):
        """根据规则类型生成后缀"""
        if rule_type == "随机":
            return f"{np.random.randint(0, 10000):04d}"
        
        # 连号规则
        elif rule_type == "七连号":
            # 简化的七连号生成逻辑，直接返回4位相同数字作为后缀
            # 与前缀组合形成七连号
            # 确保生成各种数字的连号
            digit = str(np.random.randint(0, 10))
            return digit * 4
        elif rule_type == "六连号":
            # 六连号：手机号第6-11位形成6个连续相同数字
            # 后缀4位全部相同，与前缀的第6-7位组合形成6连号
            digit = np.random.randint(0, 10)  # 允许0-9所有数字
            # 返回4位相同数字的后缀
            return str(digit) * 4
        elif rule_type == "五连号":
            # 五连号：手机号第7-11位形成5个连续相同数字
            # 后缀4位全部相同，与前缀的第7位组合形成5连号
            digit = np.random.randint(0, 10)  # 允许0-9所有数字
            # 返回4位相同数字的后缀
            return str(digit) * 4
        elif rule_type == "四连号":
            # 四连号：手机号第8-11位形成4个连续相同数字
            digit = np.random.randint(0, 10)  # 允许0-9所有数字
            # 返回4位相同数字的后缀
            return str(digit) * 4
        elif rule_type == "三连号":
            # 三连号：手机号第9-11位形成3个连续相同数字
            digit = np.random.randint(0, 10)  # 允许0-9所有数字
            # 返回3位相同数字 + 1位随机数字
            return str(digit) * 3 + str(np.random.randint(0, 10))
        
        # 模式规则
        elif rule_type == "AAAABBBB":
            a = np.random.randint(0, 10)
            b = np.random.randint(0, 10)
            while b == a:
                b = np.random.randint(0, 10)
            return str(a) * 2 + str(b) * 2
        elif rule_type == "AAABBBCCC":
            a = np.random.randint(0, 10)
            b = np.random.randint(0, 10)
            c = np.random.randint(0, 10)
            while b == a:
                b = np.random.randint(0, 10)
            while c == a or c == b:
                c = np.random.randint(0, 10)
            return str(a) + str(b) + str(c) + str(np.random.randint(0, 10))
        elif rule_type == "AABBCCDD":
            a = np.random.randint(0, 10)
            b = np.random.randint(0, 10)
            while b == a:
                b = np.random.randint(0, 10)
            return str(a) * 2 + str(b) * 2
        elif rule_type == "ABABAB":
            a = np.random.randint(0, 10)
            b = np.random.randint(0, 10)
            while b == a:
                b = np.random.randint(0, 10)
            return str(a) + str(b) + str(a) + str(b)
        elif rule_type == "AAABBB":
            a = np.random.randint(0, 10)
            b = np.random.randint(0, 10)
            while b == a:
                b = np.random.randint(0, 10)
            return str(a) * 2 + str(b) * 2
        elif rule_type == "AAABB":
            a = np.random.randint(0, 10)
            b = np.random.randint(0, 10)
            while b == a:
                b = np.random.randint(0, 10)
            return str(a) * 2 + str(b) + str(np.random.randint(0, 10))
        elif rule_type == "AABBCC":
            a = np.random.randint(0, 10)
            b = np.random.randint(0, 10)
            while b == a:
                b = np.random.randint(0, 10)
            return str(a) * 2 + str(b) * 2
        elif rule_type == "AABB":
            a = np.random.randint(0, 10)
            b = np.random.randint(0, 10)
            while b == a:
                b = np.random.randint(0, 10)
            return str(a) * 2 + str(b) * 2
        elif rule_type == "AAAB":
            a = np.random.randint(0, 10)
            return str(a) * 3 + str(np.random.randint(0, 10))
        
        # 连续号码规则
        elif rule_type == "ABCD":
            start = np.random.randint(0, 7)  # 0-6开始，确保4位连续
            return ''.join(str((start + i) % 10) for i in range(4))
        elif rule_type == "ABCDE":
            start = np.random.randint(0, 6)  # 0-5开始，确保5位连续
            return ''.join(str((start + i) % 10) for i in range(4))
        elif rule_type == "ABCDEF":
            start = np.random.randint(0, 5)  # 0-4开始，确保6位连续
            return ''.join(str((start + i) % 10) for i in range(4))
        elif rule_type == "ABCDEFG":
            start = np.random.randint(0, 4)  # 0-3开始，确保7位连续
            return ''.join(str((start + i) % 10) for i in range(4))
        elif rule_type == "ABCDEFGH":
            start = np.random.randint(0, 3)  # 0-2开始，确保8位连续
            return ''.join(str((start + i) % 10) for i in range(4))
        elif rule_type == "ABCABC":
            a = np.random.randint(0, 10)
            b = np.random.randint(0, 10)
            c = np.random.randint(0, 10)
            while b == a:
                b = np.random.randint(0, 10)
            while c == a or c == b:
                c = np.random.randint(0, 10)
            return str(a) + str(b) + str(c) + str(a)
        
        # 默认随机
        return f"{np.random.randint(0, 10000):04d}"
    
    def generate_custom_suffix(self, pattern):
        """根据自定义模式生成后缀"""
        suffix = ""
        for char in pattern:
            if char == 'X':
                suffix += str(np.random.randint(0, 10))
            else:
                suffix += char
        return suffix
    
    def get_area_code_by_prefix(self, prefix, system_data):
        """根据号码前缀获取区号"""
        if system_data.empty:
            return ""
        
        # 适配不同的列名
        segment_column = '号段'
        area_code_column = '区号' if '区号' in system_data.columns else 'area_code'
        
        # 查找匹配的号码段
        matching_records = system_data[system_data[segment_column].astype(str).str.startswith(prefix)]
        
        if not matching_records.empty:
            # 返回第一个匹配的区号
            area_code = str(matching_records.iloc[0][area_code_column])
            # 确保区号格式正确（前面加0）
            if area_code and not area_code.startswith('0'):
                area_code = '0' + area_code
            return area_code
        else:
            return ""
    
    def get_segments_by_area_code(self, area_code, system_data):
        """根据区号获取所有对应的号码段"""
        if system_data.empty:
            return []
        
        # 确保区号格式正确
        if area_code and not area_code.startswith('0'):
            area_code = '0' + area_code
        
        # 如果使用SQLite数据库，直接查询数据库
        if hasattr(self.db_manager, 'system_sqlite_path') and os.path.exists(self.db_manager.system_sqlite_path):
            try:
                conn = sqlite3.connect(self.db_manager.system_sqlite_path)
                cursor = conn.cursor()
                cursor.execute("SELECT DISTINCT segment FROM phone_segments WHERE area_code = ?", (area_code,))
                segments = [row[0] for row in cursor.fetchall()]
                conn.close()
                return segments
            except Exception as e:
                print(f"SQLite查询失败: {e}")
        
        # 回退到DataFrame查询
        area_code_column = '区号' if '区号' in system_data.columns else 'area_code'
        segment_column = '号段'
        
        # 查找匹配的号码段
        matching_records = system_data[system_data[area_code_column].astype(str) == area_code]
        
        if not matching_records.empty:
            # 返回所有匹配的号码段
            segments = matching_records[segment_column].astype(str).unique().tolist()
            return segments
        else:
            return []
    
    def get_segments_by_operator(self, operator, system_data):
        """根据运营商获取所有对应的号码段"""
        if system_data.empty or not operator:
            return []
        
        # 如果使用SQLite数据库，直接查询数据库
        if hasattr(self.db_manager, 'system_sqlite_path') and os.path.exists(self.db_manager.system_sqlite_path):
            try:
                conn = sqlite3.connect(self.db_manager.system_sqlite_path)
                cursor = conn.cursor()
                cursor.execute("SELECT DISTINCT segment FROM phone_segments WHERE operator LIKE ?", (f'%{operator}%',))
                segments = [row[0] for row in cursor.fetchall()]
                conn.close()
                # 确保返回足够多的号码段并随机排序
                np.random.shuffle(segments)
                return segments
            except Exception as e:
                print(f"SQLite查询失败: {e}")
        
        # 回退到DataFrame查询
        operator_column = '服务商' if '服务商' in system_data.columns else 'operator'
        segment_column = '号段'
        
        # 查找匹配的号码段
        matching_records = system_data[system_data[operator_column].astype(str).str.contains(operator)]
        
        if not matching_records.empty:
            # 返回所有匹配的号码段
            segments = matching_records[segment_column].astype(str).unique().tolist()
            # 随机排序号码段，确保不总是从同一个开始
            np.random.shuffle(segments)
            return segments
        else:
            return []
    
    def get_segments_by_city(self, city, system_data):
        """根据城市获取所有对应的号码段"""
        if system_data.empty:
            return []
        
        # 如果使用SQLite数据库，直接查询数据库
        if hasattr(self.db_manager, 'system_sqlite_path') and os.path.exists(self.db_manager.system_sqlite_path):
            try:
                conn = sqlite3.connect(self.db_manager.system_sqlite_path)
                cursor = conn.cursor()
                cursor.execute("SELECT DISTINCT segment FROM phone_segments WHERE city = ?", (city,))
                segments = [row[0] for row in cursor.fetchall()]
                conn.close()
                return segments
            except Exception as e:
                print(f"SQLite查询失败: {e}")
        
        # 回退到DataFrame查询
        city_column = '城市' if '城市' in system_data.columns else 'city'
        segment_column = '号段'
        
        # 查找匹配的号码段
        matching_records = system_data[system_data[city_column].astype(str) == city]
        
        if not matching_records.empty:
            # 返回所有匹配的号码段
            segments = matching_records[segment_column].astype(str).unique().tolist()
            return segments
        else:
            return []
 
class PhoneGeneratorApp(QMainWindow):
    """主应用程序"""
    
    def __init__(self):
        super().__init__()
        self.db_manager = DatabaseManager()
        self.current_phones = []
        self.generation_thread = None
        # 添加数据类型跟踪变量：'all'（全部）, 'generated'（生成）, 'imported'（导入）
        self.current_data_type = 'all'
        self.init_ui()
        # 应用启动时自动加载数据库中的号码
        self._load_phones_from_database()
    
    def init_ui(self):
        """初始化界面"""
        self.setWindowTitle("亿位号码精灵1.0")
        self.setGeometry(100, 100, 1200, 700)
        
        # 设置样式
        self.setStyleSheet("""
            QMainWindow {
                background-color: #f0f0f0;
            }
            QPushButton {
                background-color: #4CAF50;
                color: white;
                border: none;
                padding: 8px 16px;
                border-radius: 4px;
                font-size: 12px;
            }
            QPushButton:hover {
                background-color: #45a049;
            }
            QPushButton:pressed {
                background-color: #3d8b40;
            }
            QGroupBox {
                font-weight: bold;
                border: 1px solid #ccc;
                border-radius: 5px;
                margin-top: 10px;
                padding-top: 10px;
            }
            QGroupBox::title {
                subcontrol-origin: margin;
                left: 10px;
                padding: 0 5px 0 5px;
            }
        """)
        
        # 创建中央部件
        central_widget = QWidget()
        self.setCentralWidget(central_widget)
        
        # 主布局
        main_layout = QHBoxLayout(central_widget)
        
        # 左侧功能面板
        left_panel = self.create_left_panel()
        main_layout.addWidget(left_panel)
        
        # 右侧工作区
        right_panel = self.create_right_panel()
        main_layout.addWidget(right_panel)
        
        # 设置布局比例
        main_layout.setStretchFactor(left_panel, 1)
        main_layout.setStretchFactor(right_panel, 3)
        
        # 添加底部版本信息
        self.create_bottom_bar()
    
    def create_left_panel(self):
        """创建左侧功能面板"""
        left_frame = QFrame()
        left_frame.setFrameShape(QFrame.Shape.StyledPanel)
        layout = QVBoxLayout(left_frame)
        
        # 查询功能组（移到左侧最上方）
        query_group = QGroupBox("查询功能")
        query_layout = QVBoxLayout(query_group)
        
        query_input_layout = QHBoxLayout()
        query_input_layout.addWidget(QLabel("查询号码:"))
        self.query_edit = QLineEdit()
        self.query_edit.setPlaceholderText("输入11位手机号码进行查询")
        self.query_edit.setFixedWidth(150)
        query_input_layout.addWidget(self.query_edit)
        
        self.query_btn = QPushButton("查询")
        self.query_btn.clicked.connect(self.query_phone)
        query_input_layout.addWidget(self.query_btn)
        
        self.query_result_label = QLabel("")
        self.query_result_label.setStyleSheet("color: blue;")
        
        query_layout.addLayout(query_input_layout)
        query_layout.addWidget(self.query_result_label)
        
        # 导入功能组
        import_group = QGroupBox("导入功能")
        import_layout = QVBoxLayout(import_group)
        
        self.import_csv_btn = QPushButton("导入CSV文件")
        self.import_excel_btn = QPushButton("导入Excel文件")
        self.import_txt_btn = QPushButton("导入TXT文件")
        
        self.import_csv_btn.clicked.connect(lambda: self.import_file('csv'))
        self.import_excel_btn.clicked.connect(lambda: self.import_file('excel'))
        self.import_txt_btn.clicked.connect(lambda: self.import_file('txt'))
        
        import_layout.addWidget(self.import_csv_btn)
        import_layout.addWidget(self.import_excel_btn)
        import_layout.addWidget(self.import_txt_btn)
        
        # 生成功能组
        generate_group = QGroupBox("号码生成")
        generate_layout = QVBoxLayout(generate_group)
        
        # 手动输入前缀
        prefix_layout = QHBoxLayout()
        prefix_layout.addWidget(QLabel("开头数字:"))
        self.manual_prefix_edit = QLineEdit()
        self.manual_prefix_edit.setPlaceholderText("输入数字（2-7位）")
        self.manual_prefix_edit.setFixedHeight(30)
        prefix_layout.addWidget(self.manual_prefix_edit)
        
        # 区号选择
        area_code_layout = QHBoxLayout()
        area_code_layout.addWidget(QLabel("区号:"))
        self.area_code_combo = QComboBox()
        self.area_code_combo.setEditable(True)
        self.area_code_combo.setFixedHeight(30)
        self.load_area_codes()
        self.area_code_combo.setCompleter(QCompleter(self.area_code_combo.model()))
        area_code_layout.addWidget(self.area_code_combo)
        
        # 城市选择
        city_layout = QHBoxLayout()
        city_layout.addWidget(QLabel("城市:"))
        self.city_combo = QComboBox()
        self.city_combo.setEditable(True)
        self.city_combo.setFixedHeight(30)  # 增加下拉框高度
        self.load_cities()
        self.city_combo.setCompleter(QCompleter(self.city_combo.model()))
        city_layout.addWidget(self.city_combo)
        
        # 运营商选择
        operator_layout = QHBoxLayout()
        operator_layout.addWidget(QLabel("运营商:"))
        self.operator_combo = QComboBox()
        self.operator_combo.setEditable(True)
        self.operator_combo.setFixedHeight(30)  # 增加下拉框高度
        # 从data.csv加载所有运营商数据
        self.load_operators()
        self.operator_combo.setCompleter(QCompleter(self.operator_combo.model()))
        operator_layout.addWidget(self.operator_combo)
        
        # 号码规则
        rule_layout = QHBoxLayout()
        rule_layout.addWidget(QLabel("号码规则:"))
        self.rule_combo = QComboBox()
        self.rule_combo.setFixedHeight(30)
        self.rule_combo.addItems(["随机", "七连号", "六连号", "五连号", "四连号", "三连号", 
                                 "AAAABBBB", "AAABBBCCC", "AABBCCDD", "ABABAB", "AAABBB", 
                                 "AAABB", "AABBCC", "AABB", "AAAB", "ABCD", "ABCDE", 
                                 "ABCDEF", "ABCDEFG", "ABCDEFGH", "ABCABC"])
        rule_layout.addWidget(self.rule_combo)
        
        # 必需数字
        required_layout = QHBoxLayout()
        required_layout.addWidget(QLabel("必需数字:"))
        self.required_digits_edit = QLineEdit()
        self.required_digits_edit.setPlaceholderText("输入号码中必须出现的数字（可选）")
        self.required_digits_edit.setFixedHeight(30)
        required_layout.addWidget(self.required_digits_edit)
        
        # 排除数字
        exclude_layout = QHBoxLayout()
        exclude_layout.addWidget(QLabel("排除数字:"))
        self.exclude_digits_edit = QLineEdit()
        self.exclude_digits_edit.setPlaceholderText("输入末尾或中间不能出现的数字（可选）")
        self.exclude_digits_edit.setFixedHeight(30)
        exclude_layout.addWidget(self.exclude_digits_edit)
        
        # 生成数量
        count_layout = QHBoxLayout()
        count_layout.addWidget(QLabel("生成数量:"))
        self.count_spin = QSpinBox()
        self.count_spin.setRange(1, 10000)
        self.count_spin.setValue(100)
        count_layout.addWidget(self.count_spin)
        
        # 生成按钮
        self.generate_btn = QPushButton("生成号码")
        self.generate_btn.clicked.connect(self.generate_phones)
        
        generate_layout.addLayout(prefix_layout)
        generate_layout.addLayout(area_code_layout)
        generate_layout.addLayout(city_layout)
        generate_layout.addLayout(operator_layout)
        generate_layout.addLayout(rule_layout)
        generate_layout.addLayout(required_layout)
        generate_layout.addLayout(exclude_layout)
        generate_layout.addLayout(count_layout)
        generate_layout.addWidget(self.generate_btn)
        
        # 网站链接信息（替换原导出功能位置）
        website_group = QGroupBox("广告赞助")
        website_layout = QVBoxLayout(website_group)
        
        # 三行文字，包含网站链接
        website_text1 = QLabel('<a href="https://mp.weixin.qq.com/mp/homepage?__biz=MzI3ODkwODk0Mw==&hid=1&sn=bee10bc0cc8c62929fd82ca7a1904c1a&scene=18">全国园区招商（核定或扶持奖励），解决无票难题</a>')
        website_text1.setAlignment(Qt.AlignmentFlag.AlignCenter)
        website_text1.setOpenExternalLinks(True)        
        website_text1.setStyleSheet("color: #333333; font-weight: bold;")
        
        website_text2 = QLabel('<a href="http://igongsi.com/">香港公司、日本、新加坡公司注册+年审+财税合规</a>')
        website_text2.setAlignment(Qt.AlignmentFlag.AlignCenter)
        website_text2.setOpenExternalLinks(True)  
        website_text2.setStyleSheet("color: #333333;")
        
        # 创建可点击的网址标签
        website_link = QLabel('<a href="http://igongsi.com/?id=16">双免个体</a>|<a href="http://www.eachwe.com">上海/海南公司注册:17811973989</a>')
        website_link.setAlignment(Qt.AlignmentFlag.AlignCenter)
        website_link.setOpenExternalLinks(True)  # 允许打开外部链接
        website_link.setStyleSheet("color: #0066cc; font-weight: bold;")
        
        website_layout.addWidget(website_text1)
        website_layout.addWidget(website_text2)
        website_layout.addWidget(website_link)
        
        # 添加到左侧布局
        layout.addWidget(query_group)
        layout.addWidget(import_group)
        layout.addWidget(generate_group)
        layout.addWidget(website_group)
        layout.addStretch()
        
        return left_frame
    
    def create_right_panel(self):
        """创建右侧工作区"""
        right_frame = QFrame()
        right_frame.setFrameShape(QFrame.Shape.StyledPanel)
        layout = QVBoxLayout(right_frame)
        
        # 标签页
        self.tab_widget = QTabWidget()
        
        # 号码显示标签页
        self.phone_tab = QWidget()
        phone_layout = QVBoxLayout(self.phone_tab)
        
        # 移除了查询功能，已移至左侧
        
        # 号码列表（分页显示）- 改为4列表格显示
        self.phone_table = QTableWidget()
        self.phone_table.setColumnCount(4)
        self.phone_table.setHorizontalHeaderLabels(["第1列", "第2列", "第3列", "第4列"])
        # 设置各列宽度平均分布
        self.phone_table.horizontalHeader().setSectionResizeMode(QHeaderView.ResizeMode.Stretch)
        self.phone_table.setEditTriggers(QTableWidget.EditTrigger.NoEditTriggers)
        self.phone_table.setSelectionBehavior(QTableWidget.SelectionBehavior.SelectRows)
        self.status_label = QLabel("就绪")
        
        # 分页控件
        page_layout = QHBoxLayout()
        page_layout.addWidget(QLabel("页码:"))
        self.page_spin = QSpinBox()
        self.page_spin.setMinimum(1)
        self.page_spin.setMaximum(100)
        self.page_spin.setValue(1)
        self.page_spin.valueChanged.connect(self.load_page)
        page_layout.addWidget(self.page_spin)
        
        page_layout.addWidget(QLabel("每页显示:"))
        self.page_size_combo = QComboBox()
        self.page_size_combo.addItems(["20", "40", "60", "80", "100"])
        self.page_size_combo.setCurrentText("80")
        self.page_size_combo.currentTextChanged.connect(self.load_page)
        page_layout.addWidget(self.page_size_combo)
        
        page_layout.addStretch()
        
        # 功能按钮
        button_layout = QHBoxLayout()
        self.deduplicate_btn = QPushButton("去重")
        self.sort_btn = QPushButton("排序")
        self.shuffle_btn = QPushButton("乱序")
        self.filter_btn = QPushButton("去除非手机号")
        self.copy_btn = QPushButton("复制")
        self.clear_btn = QPushButton("清空")
        
        self.deduplicate_btn.clicked.connect(self.deduplicate_phones)
        self.sort_btn.clicked.connect(self.sort_phones)
        self.shuffle_btn.clicked.connect(self.shuffle_phones)
        self.filter_btn.clicked.connect(self.filter_phones)
        self.copy_btn.clicked.connect(self.copy_phones)
        self.clear_btn.clicked.connect(self.clear_phones)
        
        button_layout.addWidget(self.deduplicate_btn)
        button_layout.addWidget(self.sort_btn)
        button_layout.addWidget(self.shuffle_btn)
        button_layout.addWidget(self.filter_btn)
        button_layout.addWidget(self.copy_btn)
        button_layout.addWidget(self.clear_btn)
        
        # 导出功能（移到功能键下方）
        export_layout = QHBoxLayout()
        
        
        self.export_all_check = QCheckBox("导出全部号码")
        self.export_all_check.setChecked(True)  # 默认选中
        self.export_city_check = QCheckBox("按城市导出")
        self.export_operator_check = QCheckBox("按运营商导出")
        self.export_duplicate_check = QCheckBox("按重复次数导出")
        
        # 添加导出按钮
        self.export_btn = QPushButton("按条件导出手机号码")
        self.export_btn.setStyleSheet("background-color: #4CAF50; color: white; font-weight: bold;")
        self.export_btn.clicked.connect(self.export_phones)
        
        # 将组件添加到布局
        export_layout.addWidget(self.export_all_check)
        export_layout.addWidget(self.export_city_check)
        export_layout.addWidget(self.export_operator_check)
        export_layout.addWidget(self.export_duplicate_check)
        export_layout.addStretch()
        export_layout.addWidget(self.export_btn)
        
        phone_layout.addWidget(QLabel("生成的手机号码:"))
        phone_layout.addWidget(self.phone_table)
        phone_layout.addLayout(page_layout)
        phone_layout.addLayout(button_layout)
        phone_layout.addLayout(export_layout)  # 添加导出功能布局
        phone_layout.addWidget(self.status_label)
        
        # 分页相关变量
        self.current_page = 1
        self.page_size = 80
        self.all_phones = []
        
        # 统计信息标签页
        self.stats_tab = QWidget()
        stats_layout = QVBoxLayout(self.stats_tab)
        
        self.stats_table = QTableWidget()
        self.stats_table.setColumnCount(3)
        self.stats_table.setHorizontalHeaderLabels(["统计项", "数量", "百分比"])
        
        stats_layout.addWidget(QLabel("统计信息:"))
        stats_layout.addWidget(self.stats_table)
        
        # 添加到标签页
        self.tab_widget.addTab(self.phone_tab, "号码列表")
        self.tab_widget.addTab(self.stats_tab, "统计信息")
        
        # 进度条
        self.progress_bar = QProgressBar()
        self.progress_bar.setVisible(False)
        
        layout.addWidget(self.tab_widget)
        layout.addWidget(self.progress_bar)
        
        return right_frame
    
    def create_bottom_bar(self):
        """创建底部版本信息栏"""
        # 创建底部状态栏
        status_bar = self.statusBar()
        
        # 添加版本信息
        version_label = QLabel("亿位号码精灵 v1.0 | Copyright © 20245 亿位信息 | 技术支持: 159-2125-2989")
        version_label.setStyleSheet("color: #666666; font-size: 12px; padding: 2px;")
        
        # 添加升级链接
        upgrade_label = QLabel('<a href="http://www.haomamofang.com">升级最新版</a>')
        upgrade_label.setStyleSheet("color: #0066cc; font-size: 14px; padding: 2px; font-weight: bold;")
        upgrade_label.setOpenExternalLinks(True)  # 允许打开外部链接
        
        # 添加到状态栏
        status_bar.addPermanentWidget(version_label)
        status_bar.addPermanentWidget(upgrade_label)  # 添加升级链接到状态栏
    
    def load_area_codes(self):
        """从数据库加载所有区号数据"""
        try:
            # 优先从数据库加载数据
            if hasattr(self.db_manager, 'system_sqlite_path') and os.path.exists(self.db_manager.system_sqlite_path):
                try:
                    conn = sqlite3.connect(self.db_manager.system_sqlite_path)
                    cursor = conn.cursor()
                    cursor.execute("SELECT DISTINCT area_code FROM phone_segments WHERE area_code IS NOT NULL AND area_code != '' ORDER BY area_code")
                    area_codes = [row[0] for row in cursor.fetchall()]
                    conn.close()
                    
                    self.area_code_combo.clear()
                    self.area_code_combo.addItem("所有区号")  # 添加默认选项
                    
                    # 确保区号格式正确
                    formatted_codes = []
                    for code in area_codes:
                        code_str = str(code)
                        if code_str and not code_str.startswith('0'):
                            code_str = '0' + code_str
                        formatted_codes.append(code_str)
                    
                    self.area_code_combo.addItems(sorted(list(set(formatted_codes))))
                    return
                except Exception as e:
                    print(f"从数据库加载区号失败: {e}")
            
            # 数据库加载失败时，回退到CSV方式
            print("从CSV加载区号数据")
            # 尝试不同的编码方式
            for encoding in ['utf-8', 'gbk', 'gb2312', 'latin1']:
                try:
                    df = pd.read_csv('data.csv', encoding=encoding)
                    area_codes = df.iloc[:, 5].dropna().unique().tolist()  # 第6列是区号
                    self.area_code_combo.clear()
                    self.area_code_combo.addItem("所有区号")  # 添加默认选项
                    # 确保区号前有0
                    formatted_codes = []
                    for code in area_codes:
                        code_str = str(code)
                        if code_str and not code_str.startswith('0'):
                            code_str = '0' + code_str
                        formatted_codes.append(code_str)
                    self.area_code_combo.addItems(formatted_codes)
                    return
                except UnicodeDecodeError:
                    continue
            # 如果所有编码都失败，使用默认选项
            self.area_code_combo.clear()
            self.area_code_combo.addItem("所有区号")
        except Exception as e:
            print(f"加载区号数据失败: {e}")
            self.area_code_combo.clear()
            self.area_code_combo.addItem("所有区号")

    def load_cities(self):
        """从数据库加载城市列表"""
        try:
            # 优先从数据库加载数据
            if hasattr(self.db_manager, 'system_sqlite_path') and os.path.exists(self.db_manager.system_sqlite_path):
                try:
                    conn = sqlite3.connect(self.db_manager.system_sqlite_path)
                    cursor = conn.cursor()
                    # 查询城市和省份，确保显示完整的城市列表
                    cursor.execute("SELECT DISTINCT city FROM phone_segments WHERE city IS NOT NULL AND city != '' ORDER BY city")
                    cities = [row[0] for row in cursor.fetchall()]
                    conn.close()
                    
                    self.city_combo.clear()
                    self.city_combo.addItem("全部")  # 添加默认选项
                    # 添加所有城市，确保去重和排序
                    self.city_combo.addItems(sorted(list(set(cities))))
                    return
                except Exception as e:
                    print(f"从数据库加载城市失败: {e}")
            
            # 数据库加载失败时，回退到CSV方式
            print("从CSV加载城市数据")
            # 尝试不同的编码方式
            for encoding in ['utf-8', 'gbk', 'gb2312', 'latin1']:
                try:
                    df = pd.read_csv('data.csv', encoding=encoding)
                    cities = df.iloc[:, 2].dropna().unique().tolist()  # 第3列是城市
                    self.city_combo.clear()
                    self.city_combo.addItem("全部")  # 添加默认选项
                    self.city_combo.addItems(cities)
                    return
                except UnicodeDecodeError:
                    continue
            # 如果所有编码都失败，使用默认选项
            self.city_combo.clear()
            self.city_combo.addItem("全部")
        except Exception as e:
            print(f"加载城市数据失败: {e}")
            self.city_combo.clear()
            self.city_combo.addItem("全部")
    
    def load_operators(self):
        """从数据库加载运营商列表"""
        try:
            # 优先从数据库加载数据
            if hasattr(self.db_manager, 'system_sqlite_path') and os.path.exists(self.db_manager.system_sqlite_path):
                try:
                    conn = sqlite3.connect(self.db_manager.system_sqlite_path)
                    cursor = conn.cursor()
                    cursor.execute("SELECT DISTINCT operator FROM phone_segments WHERE operator IS NOT NULL AND operator != '' ORDER BY operator")
                    operators = [row[0] for row in cursor.fetchall()]
                    conn.close()
                    
                    # 添加"全部"选项并去重排序
                    all_operators = ["全部"] + sorted(list(set(operators)))
                    self.operator_combo.clear()
                    self.operator_combo.addItems(all_operators)
                    return
                except Exception as e:
                    print(f"从数据库加载运营商失败: {e}")
            
            # 数据库加载失败时，回退到CSV方式
            print("从CSV加载运营商数据")
            # 尝试不同的编码方式
            for encoding in ['utf-8', 'gbk', 'gb2312', 'latin1']:
                try:
                    df = pd.read_csv('data.csv', encoding=encoding)
                    operators = df['服务商'].unique().tolist()
                    # 添加"全部"选项并去重排序
                    all_operators = ["全部"] + sorted(list(set(operators)))
                    self.operator_combo.clear()
                    self.operator_combo.addItems(all_operators)
                    return
                except UnicodeDecodeError:
                    continue
            # 如果所有编码都失败，使用默认运营商列表
            self.operator_combo.clear()
            self.operator_combo.addItems(["全部", "中国移动", "中国联通", "中国电信"])
        except Exception as e:
            # 如果读取失败，使用默认运营商列表
            print(f"加载运营商数据失败: {e}")
            self.operator_combo.clear()
            self.operator_combo.addItems(["全部", "中国移动", "中国联通", "中国电信"])
    
    def import_file(self, file_type):
        """导入文件（支持多文件选择）"""
        file_filter = ""
        if file_type == 'csv':
            file_filter = "CSV文件 (*.csv)"
        elif file_type == 'excel':
            file_filter = "Excel文件 (*.xlsx *.xls)"
        elif file_type == 'txt':
            file_filter = "文本文件 (*.txt)"
        
        # 使用getOpenFileNames支持多文件选择
        file_paths, _ = QFileDialog.getOpenFileNames(self, f"选择{file_type.upper()}文件", "", file_filter)
        
        if file_paths:
            total_valid_count = 0
            total_invalid_count = 0
            
            try:
                for file_path in file_paths:
                    # 尝试多种编码格式，优先支持中文编码
                    if file_type == 'csv':
                        # 尝试多种编码格式
                        encodings = ['utf-8', 'gbk', 'gb2312', 'cp936']
                        df = None
                        for encoding in encodings:
                            try:
                                # 使用header=None避免第一行被当作表头，确保所有数据行都被读取
                                df = pd.read_csv(file_path, encoding=encoding, header=None)
                                print(f"成功读取CSV文件: {file_path}, 编码: {encoding}, 行数: {len(df)}")
                                break
                            except UnicodeDecodeError:
                                continue
                        if df is None:
                            raise ValueError(f"无法识别文件编码: {file_path}，请尝试转换文件为UTF-8或GBK格式")
                            
                    elif file_type == 'excel':
                        # 尝试导入openpyxl（如果系统中已安装）
                        try:
                            import openpyxl
                        except ImportError:
                            QMessageBox.information(self, "正在安装依赖", "正在安装openpyxl库，请稍候...")
                            import subprocess
                            import sys
                            subprocess.check_call([sys.executable, "-m", "pip", "install", "openpyxl"])
                        df = pd.read_excel(file_path)
                        
                    elif file_type == 'txt':
                        # 尝试多种编码格式
                        encodings = ['utf-8-sig', 'utf-8', 'gbk', 'gb2312', 'cp936']  # 优先使用utf-8-sig处理BOM
                        phones = []
                        success = False
                        
                        for encoding in encodings:
                            try:
                                with open(file_path, 'r', encoding=encoding) as f:
                                    lines = f.readlines()
                                
                                phones = []
                                # 直接处理每一行，包括第一行，不做过度清理
                                for line in lines:
                                    # 简单去除行首尾空白字符
                                    line = line.strip()
                                    if not line:  # 跳过空行
                                        continue
                                    
                                    # 支持多种分隔符分割号码
                                    numbers = re.split(r'[,;\t\s]+', line)
                                    
                                    # 直接添加原始号码，保留格式，让save_user_phones去验证
                                    phones.extend([num.strip() for num in numbers if num.strip()])
                                
                                success = True
                                break
                            except UnicodeDecodeError:
                                continue
                        
                        if not success:
                            raise ValueError(f"无法识别文件编码: {file_path}，请尝试转换文件为UTF-8或GBK格式")
                        
                        df = pd.DataFrame(phones, columns=['phone'])
                    
                    # 提取手机号码
                    phones = []
                    for col in df.columns:
                        phones.extend(df[col].astype(str).tolist())
                    
                    # 验证并保存
                    valid_count, invalid_phones, all_valid_phones = self.db_manager.save_user_phones(phones, os.path.basename(file_path))
                    
                    # 累计统计
                    total_valid_count += valid_count
                    total_invalid_count += len(invalid_phones)
                    
                    # 将当前文件的所有有效号码添加到总列表
                    if not hasattr(self, 'imported_phones_list'):
                        self.imported_phones_list = []
                    self.imported_phones_list.extend(all_valid_phones)
                
                # 显示总体结果
                self.status_label.setText(f"导入完成: 有效号码 {total_valid_count} 个, 无效号码 {total_invalid_count} 个")
                
                if total_invalid_count > 0:
                    QMessageBox.warning(self, "无效号码", f"发现 {total_invalid_count} 个无效号码，已自动过滤")
                
                # 导入成功后，切换到只显示导入的号码
                self.current_data_type = 'imported'
                
                # 直接使用导入的所有号码（包括重复的）更新UI
                if hasattr(self, 'imported_phones_list'):
                    self.all_phones = self.imported_phones_list
                    self.current_phones = self.all_phones
                    
                    # 重置页码并加载第一页数据
                    self.current_page = 1
                    self.page_spin.setValue(1)
                    
                    # 调用load_page加载数据
                    self.load_page()
                    
                    # 更新统计信息
                    self.update_statistics()
                    
                    print(f"UI更新完成: 显示所有{len(self.imported_phones_list)}个导入的号码（包括重复的）")
                else:
                    # 如果没有导入的号码列表，从数据库加载
                    self._load_phones_from_database()
                
                # 显示导入文件数量信息
                QMessageBox.information(self, "导入成功", f"成功导入 {len(file_paths)} 个文件")
                
            except Exception as e:
                QMessageBox.critical(self, "导入错误", f"导入文件时出错: {str(e)}")
    
    def generate_phones(self):
        """生成手机号码"""
        if self.generation_thread and self.generation_thread.isRunning():
            self.generation_thread.requestInterruption()
            return
        
        # 检查手工输入的前缀
        manual_prefix = self.manual_prefix_edit.text().strip()
        #if not manual_prefix:
        #    QMessageBox.warning(self, "输入错误", "请输入15-7位数字作为号码前缀")
        #    return
        
        # 验证手工输入的前缀
        #if not manual_prefix.isdigit() or len(manual_prefix) < 5 or len(manual_prefix) > 7:
         #   QMessageBox.warning(self, "输入错误", "请输入5-7位数字作为号码前缀")
        #    return
        
        # 获取区号
        area_code = self.area_code_combo.currentText()
        
        # 获取必需数字
        required_digits = self.required_digits_edit.text().strip()
        
        # 获取排除数字
        exclude_digits = self.exclude_digits_edit.text().strip()
        
        # 获取号码规则
        rule_type = self.rule_combo.currentText()
        
        # 构建生成规则
        rules = {
            'manual_prefix': manual_prefix,
            'area_code': area_code,
            'required_digits': required_digits,
            'exclude_digits': exclude_digits,
            'rule_type': rule_type,
            'city': self.city_combo.currentText() if self.city_combo.currentText() != "全部" else "",
            'operator': self.operator_combo.currentText() if self.operator_combo.currentText() != "全部" else ""
        }
        
        count = self.count_spin.value()
        
        # 创建进度弹窗
        self.progress_dialog = ProgressDialog(self, "正在生成号码")
        self.progress_dialog.cancel_btn.clicked.connect(self.stop_generation)
        
        # 创建并启动生成线程
        self.generation_thread = PhoneGeneratorThread(rules, count)
        self.generation_thread.progress_updated.connect(self.update_progress)
        self.generation_thread.generation_finished.connect(self.on_generation_finished)
        self.generation_thread.generation_error.connect(self.on_generation_error)
        self.generation_thread.start()
        
        # 显示进度弹窗
        self.progress_dialog.show()
        
        self.status_label.setText("正在生成号码...")
        self.generate_btn.setText("停止生成")
    
    def stop_generation(self):
        """停止生成"""
        if self.generation_thread and self.generation_thread.isRunning():
            self.generation_thread.requestInterruption()
            self.generation_thread.wait()
        
        # 关闭进度弹窗
        if hasattr(self, 'progress_dialog') and self.progress_dialog:
            self.progress_dialog.close()
            self.progress_dialog = None
        
        self.generate_btn.setText("生成号码")
        self.status_label.setText("生成已取消")
    
    def update_progress(self, value):
        """更新进度"""
        if hasattr(self, 'progress_dialog') and self.progress_dialog:
            self.progress_dialog.update_progress(value, f"正在生成号码... {value}%")
        else:
            self.progress_bar.setValue(value)
    
    def load_page(self):
        """加载指定页码的号码"""
        # 优先使用内存中的数据（在排序、乱序等操作后）
        if hasattr(self, 'all_phones') and self.all_phones:
            # 获取当前页码和每页大小
            self.current_page = self.page_spin.value()
            self.page_size = int(self.page_size_combo.currentText())
            
            # 计算起始和结束索引
            start_idx = (self.current_page - 1) * self.page_size
            end_idx = min(start_idx + self.page_size, len(self.all_phones))
            
            # 显示当前页的号码
            page_phones = self.all_phones[start_idx:end_idx]
            
            # 更新分页控件
            total_count = len(self.all_phones)
            total_pages = max(1, (total_count + self.page_size - 1) // self.page_size)
            self.page_spin.setMaximum(total_pages)
            
            # 确保页码有效
            self.current_page = max(1, min(self.current_page, total_pages))
            self.page_spin.setValue(self.current_page)
            
            # 清空表格
            self.phone_table.setRowCount(0)
            
            # 计算需要的行数（每行4个号码）
            rows_needed = (len(page_phones) + 3) // 4  # 向上取整
            self.phone_table.setRowCount(rows_needed)
            
            # 批量插入数据，提高加载速度
            for i, phone in enumerate(page_phones):
                row = i // 4
                col = i % 4
                item = QTableWidgetItem(phone)
                item.setTextAlignment(Qt.AlignmentFlag.AlignCenter)
                self.phone_table.setItem(row, col, item)
            
            # 更新状态显示
            self.status_label.setText(f"显示第 {self.current_page} 页，共 {total_pages} 页，当前显示 {len(page_phones)} 个号码，共有 {total_count} 个号码")
            return
        
        # 如果内存中没有数据，从数据库加载
        elif hasattr(self, 'db_manager'):
            try:
                # 优化：单次连接完成查询和计数，提高效率
                conn = sqlite3.connect(self.db_manager.user_db_path)
                cursor = conn.cursor()
                
                # 获取当前页面大小
                self.page_size = int(self.page_size_combo.currentText())
                
                # 根据当前数据类型构建查询
                if self.current_data_type == 'generated':
                    # 只查询生成的号码
                    cursor.execute("SELECT COUNT(*) FROM generated_numbers")
                    total_count = cursor.fetchone()[0]
                    
                    cursor.execute('''
                        SELECT phone_number, id FROM generated_numbers
                        ORDER BY id
                        LIMIT ? OFFSET ?
                    ''', (self.page_size, (self.current_page - 1) * self.page_size))
                elif self.current_data_type == 'imported':
                    # 只查询导入的号码
                    cursor.execute("SELECT COUNT(*) FROM phone_numbers")
                    total_count = cursor.fetchone()[0]
                    
                    cursor.execute('''
                        SELECT phone_number, id FROM phone_numbers
                        ORDER BY id
                        LIMIT ? OFFSET ?
                    ''', (self.page_size, (self.current_page - 1) * self.page_size))
                else:
                    # 查询所有号码（默认）
                    # 先检查是否有生成的号码
                    cursor.execute("SELECT COUNT(*) FROM generated_numbers")
                    generated_count = cursor.fetchone()[0]
                    
                    # 检查是否有导入的号码
                    cursor.execute("SELECT COUNT(*) FROM phone_numbers")
                    imported_count = cursor.fetchone()[0]
                    
                    # 计算总数
                    total_count = generated_count + imported_count
                    
                    # 使用UNION ALL合并两个表的数据，并进行分页查询
                    cursor.execute('''
                        SELECT phone_number FROM (
                            SELECT phone_number, id, 1 as source FROM generated_numbers
                            UNION ALL
                            SELECT phone_number, id, 2 as source FROM phone_numbers
                        ) combined
                        ORDER BY id
                        LIMIT ? OFFSET ?
                    ''', (self.page_size, (self.current_page - 1) * self.page_size))
                page_phones = [row[0] for row in cursor.fetchall()]
                
                conn.close()
                
                # 更新分页控件
                total_pages = max(1, (total_count + self.page_size - 1) // self.page_size)
                self.page_spin.setMaximum(total_pages)
                
                # 确保页码有效
                self.current_page = max(1, min(self.current_page, total_pages))
                self.page_spin.setValue(self.current_page)
                
                # 清空表格
                self.phone_table.setRowCount(0)
                
                # 计算需要的行数（每行4个号码）
                rows_needed = (len(page_phones) + 3) // 4  # 向上取整
                self.phone_table.setRowCount(rows_needed)
                
                # 批量插入数据，提高加载速度
                for i, phone in enumerate(page_phones):
                    row = i // 4
                    col = i % 4
                    item = QTableWidgetItem(phone)
                    item.setTextAlignment(Qt.AlignmentFlag.AlignCenter)
                    self.phone_table.setItem(row, col, item)
                
                # 更新状态显示
                self.status_label.setText(f"显示第 {self.current_page} 页，共 {total_pages} 页，当前显示 {len(page_phones)} 个号码，共有 {total_count} 个号码")
                return
            except Exception as e:
                print(f"从数据库加载页面失败: {e}")
        
        # 如果数据库加载失败，回退到内存列表
        if not self.all_phones:
            return
        
        # 获取当前页码和每页大小
        self.current_page = self.page_spin.value()
        self.page_size = int(self.page_size_combo.currentText())
        
        # 计算起始和结束索引
        start_idx = (self.current_page - 1) * self.page_size
        end_idx = min(start_idx + self.page_size, len(self.all_phones))
        
        # 显示当前页的号码
        page_phones = self.all_phones[start_idx:end_idx]
        
        # 清空表格
        self.phone_table.setRowCount(0)
        
        # 计算需要的行数（每行4个号码）
        rows_needed = (len(page_phones) + 3) // 4  # 向上取整
        self.phone_table.setRowCount(rows_needed)
        
        # 批量插入数据
        for i, phone in enumerate(page_phones):
            row = i // 4
            col = i % 4
            item = QTableWidgetItem(phone)
            item.setTextAlignment(Qt.AlignmentFlag.AlignCenter)
            self.phone_table.setItem(row, col, item)
        
        # 更新状态显示
        total_pages = max(1, (len(self.all_phones) + self.page_size - 1) // self.page_size)
        total_count = len(self.all_phones)
        self.status_label.setText(f"显示第 {self.current_page} 页，共 {total_pages} 页，当前显示 {len(page_phones)} 个号码，共有 {total_count} 个号码")
    
    def _load_next_batch(self):
        """逐步加载下一批数据"""
        if self._loading_timer.isActive():
            # 加载下一批数据
            page_phones = self._current_page_phones
            batch_end = min(self._current_loading_index + self._loading_batch_size, len(page_phones))
            
            # 填充当前批次的数据
            for i in range(self._current_loading_index, batch_end):
                row = i // 4
                col = i % 4
                item = QTableWidgetItem(page_phones[i])
                item.setTextAlignment(Qt.AlignmentFlag.AlignCenter)
                self.phone_table.setItem(row, col, item)
            
            # 更新索引
            self._current_loading_index = batch_end
            
            # 如果所有数据都加载完成，停止定时器
            if self._current_loading_index >= len(page_phones):
                self._loading_timer.stop()
                # 完成加载后更新状态
                page_count = max(1, (len(self.all_phones) + self.page_size - 1) // self.page_size)
                total_count = len(self.all_phones)
                self.status_label.setText(f"显示第 {self.current_page} 页，共 {page_count} 页，当前显示 {len(page_phones)} 个号码，共有 {total_count} 个号码")
            else:
                # 继续加载下一批
                self.status_label.setText(f"正在加载第 {self.current_page} 页... ({int(self._current_loading_index/len(page_phones)*100)}%)")
    
    def deduplicate_phones(self):
        """去重功能"""
        # 先从数据库加载当前类型的号码
        self._load_phones_from_database()
        
        if not self.all_phones:
            QMessageBox.information(self, "提示", "没有号码可去重")
            return
        
        # 去重
        unique_phones = list(set(self.all_phones))
        
        if len(unique_phones) == len(self.all_phones):
            QMessageBox.information(self, "提示", "号码列表中没有重复号码")
            return
        
        self.all_phones = unique_phones
        self.current_phones = unique_phones
        self.load_page()
        
        QMessageBox.information(self, "去重完成", f"已去除 {len(self.all_phones) - len(unique_phones)} 个重复号码，剩余 {len(unique_phones)} 个号码")
    
    def sort_phones(self):
        """排序功能"""
        # 先从数据库加载当前类型的号码
        self._load_phones_from_database()
        
        if not self.all_phones:
            QMessageBox.information(self, "提示", "没有号码可排序")
            return
        
        # 按数字大小排序（先将字符串转换为整数进行比较，再转回字符串）
        self.all_phones.sort(key=lambda x: int(x))
        self.current_phones = self.all_phones
        self.load_page()
        
        QMessageBox.information(self, "排序完成", "号码已按数字大小排序")
    
    def shuffle_phones(self):
        """乱序功能"""
        # 先从数据库加载当前类型的号码
        self._load_phones_from_database()
        
        if not self.all_phones:
            QMessageBox.information(self, "提示", "没有号码可乱序")
            return
        
        # 随机打乱顺序
        import random
        random.shuffle(self.all_phones)
        self.current_phones = self.all_phones
        self.load_page()
        
        QMessageBox.information(self, "乱序完成", "号码顺序已随机打乱")
    
    def filter_phones(self):
        """去除非手机号功能"""
        # 先从数据库加载当前类型的号码
        self._load_phones_from_database()
        
        if not self.all_phones:
            QMessageBox.information(self, "提示", "没有号码可过滤")
            return
        
        # 过滤非手机号
        valid_phones = [phone for phone in self.all_phones if PhoneValidator.is_valid_phone(phone)]
        
        if len(valid_phones) == len(self.all_phones):
            QMessageBox.information(self, "提示", "所有号码都是有效的手机号")
            return
        
        removed_count = len(self.all_phones) - len(valid_phones)
        self.all_phones = valid_phones
        self.current_phones = valid_phones
        self.load_page()
        
        QMessageBox.information(self, "过滤完成", f"已去除 {removed_count} 个无效号码，剩余 {len(valid_phones)} 个有效手机号")
    
    def copy_phones(self):
        """复制功能"""
        # 先从数据库加载当前类型的号码
        self._load_phones_from_database()
        
        if not self.all_phones:
            QMessageBox.information(self, "提示", "没有号码可复制")
            return
        
        # 复制所有号码到剪贴板
        clipboard = QApplication.clipboard()
        phone_text = '\n'.join(self.all_phones)
        clipboard.setText(phone_text)
        
        QMessageBox.information(self, "复制完成", f"已复制 {len(self.all_phones)} 个号码到剪贴板")
    
    def clear_phones(self):
        """清空功能"""
        # 检查数据库中是否有号码
        try:
            conn = sqlite3.connect(self.db_manager.user_db_path)
            cursor = conn.cursor()
            
            if self.current_data_type == 'generated':
                cursor.execute("SELECT COUNT(*) FROM generated_numbers")
                count = cursor.fetchone()[0]
            elif self.current_data_type == 'imported':
                cursor.execute("SELECT COUNT(*) FROM phone_numbers")
                count = cursor.fetchone()[0]
            else:
                cursor.execute("SELECT COUNT(*) FROM generated_numbers")
                generated_count = cursor.fetchone()[0]
                cursor.execute("SELECT COUNT(*) FROM phone_numbers")
                imported_count = cursor.fetchone()[0]
                count = generated_count + imported_count
            
            conn.close()
            
            if count == 0:
                QMessageBox.information(self, "提示", "无可用号码")
                return
        except Exception:
            if not self.all_phones:
                QMessageBox.information(self, "提示", "无可用号码")
                return
        
        # 确认清空操作
        reply = QMessageBox.question(self, "确认清空", "确定要清空所有号码吗？此操作不可撤销。", 
                                   QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No)
        
        if reply == QMessageBox.StandardButton.Yes:
            # 清空数据库中的号码
            try:
                conn = sqlite3.connect(self.db_manager.user_db_path)
                cursor = conn.cursor()
                
                if self.current_data_type == 'generated':
                    cursor.execute("DELETE FROM generated_numbers")
                elif self.current_data_type == 'imported':
                    cursor.execute("DELETE FROM phone_numbers")
                else:
                    cursor.execute("DELETE FROM generated_numbers")
                    cursor.execute("DELETE FROM phone_numbers")
                
                conn.commit()
                conn.close()
            except Exception as e:
                print(f"清空数据库失败: {e}")
            
            # 清空内存中的号码
            self.all_phones = []
            self.current_phones = []
            self.phone_table.setRowCount(0)
            self.status_label.setText("已清空所有号码")
            
            # 清空统计信息
            self.stats_table.setRowCount(0)
            
            # 重置分页控件
            self.page_spin.setValue(1)
            self.page_spin.setMaximum(1)
            
            QMessageBox.information(self, "清空完成", "所有号码已清空")
    
    def on_generation_error(self, error_message):
        """处理生成错误"""
        # 关闭进度弹窗
        if hasattr(self, 'progress_dialog') and self.progress_dialog:
            self.progress_dialog.close()
            self.progress_dialog = None
        
        self.progress_bar.setVisible(False)
        self.generate_btn.setText("生成号码")
        
        QMessageBox.warning(self, "生成错误", error_message)
    
    def on_generation_finished(self, phones):
        """生成完成处理"""
        # 关闭进度弹窗
        if hasattr(self, 'progress_dialog') and self.progress_dialog:
            self.progress_dialog.close()
            self.progress_dialog = None
        
        self.progress_bar.setVisible(False)
        self.generate_btn.setText("生成号码")
        
        if phones:
            # 保存到数据库（双重保障）
            self.db_manager.save_generated_phones(phones, "自定义规则")
            
            # 生成完成后，切换到只显示生成的号码
            self.current_data_type = 'generated'
            
            # 直接从数据库加载号码，提高性能
            self._load_phones_from_database()
            
            # 重新查询生成的号码数量以更新状态
            try:
                conn = sqlite3.connect(self.db_manager.user_db_path)
                cursor = conn.cursor()
                cursor.execute("SELECT COUNT(*) FROM generated_numbers")
                generated_count = cursor.fetchone()[0]
                conn.close()
                
                # 更新状态标签
                self.status_label.setText(f"生成完成: 共 {generated_count} 个有效号码")
            except Exception:
                self.status_label.setText(f"生成完成: 请查看号码列表")
        else:
            self.status_label.setText("生成失败: 请检查系统数据库")
    
    def _load_phones_from_database(self):
        """从数据库加载号码信息"""
        try:
            conn = sqlite3.connect(self.db_manager.user_db_path)
            cursor = conn.cursor()
            
            # 清空内存中的号码列表
            self.all_phones = []
            
            # 根据当前数据类型获取对应的号码
            if self.current_data_type == 'generated':
                # 获取生成号码
                cursor.execute("SELECT phone_number FROM generated_numbers")
                self.all_phones = [row[0] for row in cursor.fetchall()]
                print(f"数据库中共有 {len(self.all_phones)} 个生成号码")
            elif self.current_data_type == 'imported':
                # 获取导入号码
                cursor.execute("SELECT phone_number FROM phone_numbers")
                self.all_phones = [row[0] for row in cursor.fetchall()]
                print(f"数据库中共有 {len(self.all_phones)} 个导入号码")
            else:
                # 获取生成号码
                cursor.execute("SELECT phone_number FROM generated_numbers")
                generated_phones = [row[0] for row in cursor.fetchall()]
                
                # 获取导入号码
                cursor.execute("SELECT phone_number FROM phone_numbers")
                imported_phones = [row[0] for row in cursor.fetchall()]
                
                # 合并所有号码
                self.all_phones = generated_phones + imported_phones
                print(f"数据库中共有 {len(self.all_phones)} 个号码（生成: {len(generated_phones)}, 导入: {len(imported_phones)}）")
            
            conn.close()
            
            # 设置当前显示的号码
            self.current_phones = self.all_phones
            
            # 重置页码并加载第一页数据
            self.current_page = 1
            self.page_spin.setValue(1)
            
            # 调用load_page加载数据
            self.load_page()
            
            # 更新统计信息
            self.update_statistics()
            
        except Exception as e:
            print(f"从数据库加载号码信息失败: {e}")
            # 错误情况下的回退处理
            self.load_page()
            self.update_statistics()
    
    def update_statistics(self):
        """更新统计信息（优化版：避免加载所有号码到内存）"""
        # 首先检查是否有数据库管理器
        if not hasattr(self, 'db_manager'):
            return
        
        try:
            conn = sqlite3.connect(self.db_manager.user_db_path)
            cursor = conn.cursor()
            
            # 获取总数但不加载所有号码
            cursor.execute("SELECT COUNT(*) FROM generated_numbers")
            generated_count = cursor.fetchone()[0]
            
            cursor.execute("SELECT COUNT(*) FROM phone_numbers")
            imported_count = cursor.fetchone()[0]
            
            total_count = generated_count + imported_count
            
            # 关闭连接
            conn.close()
            
            if total_count == 0:
                # 清空统计表格
                self.stats_table.setRowCount(0)
                return
            
            # 清空统计表格
            self.stats_table.setRowCount(0)
            
            # 只添加总数统计信息，不进行详细统计以避免加载所有号码
            # 直接设置表格数据，不使用不存在的_add_statistics_row方法
            self.stats_table.setRowCount(3)
            self.stats_table.setItem(0, 0, QTableWidgetItem("总号码数"))
            self.stats_table.setItem(0, 1, QTableWidgetItem(str(total_count)))
            self.stats_table.setItem(1, 0, QTableWidgetItem("生成号码数"))
            self.stats_table.setItem(1, 1, QTableWidgetItem(str(generated_count)))
            self.stats_table.setItem(2, 0, QTableWidgetItem("导入号码数"))
            self.stats_table.setItem(2, 1, QTableWidgetItem(str(imported_count)))
            
            # 不再进行详细统计，以避免加载所有号码到内存
            # 如需详细统计功能，可以后续优化为使用SQL聚合函数直接在数据库端计算
                
        except Exception as e:
            print(f"更新统计信息失败: {e}")
            # 清空统计表格
            self.stats_table.setRowCount(0)
    
    def export_phones(self):
        """导出手机号码"""
        # 获取导出选项
        export_all = self.export_all_check.isChecked()
        export_by_city = self.export_city_check.isChecked()
        export_by_operator = self.export_operator_check.isChecked()
        export_by_duplicate = self.export_duplicate_check.isChecked()
        
        # 准备导出的手机号码
        try:
            if export_all:
                # 导出全部号码
                export_phones = self.db_manager.get_all_phones()
                if not export_phones:
                    QMessageBox.warning(self, "导出错误", "没有可导出的手机号码")
                    return
                
                # 单独处理导出全部号码的逻辑
                file_path, _ = QFileDialog.getSaveFileName(self, "保存文件", "", "CSV文件 (*.csv);;文本文件 (*.txt)")
                if file_path:
                    try:
                        if file_path.endswith('.csv'):
                            df = pd.DataFrame(export_phones, columns=['phone_number'])
                            df.to_csv(file_path, index=False, encoding='utf-8-sig')
                        else:
                            with open(file_path, 'w', encoding='utf-8') as f:
                                for phone in export_phones:
                                    f.write(phone + '\n')
                        
                        QMessageBox.information(self, "导出成功", f"全部号码已导出到: {file_path}")
                        return
                    except Exception as e:
                        QMessageBox.critical(self, "导出错误", f"导出文件时出错: {str(e)}")
                        return
            else:
                # 其他导出方式
                # 先尝试从数据库获取所有手机号码
                if not self.current_phones:
                    # 根据当前类型（生成或导入）加载号码
                    if self.phone_type_combobox.currentText() == '生成':
                        self.current_phones = self.db_manager.get_generated_phones()
                    else:
                        self.current_phones = self.db_manager.get_imported_phones()
                
                # 再次检查是否有可导出的号码
                if not self.current_phones:
                    QMessageBox.warning(self, "导出错误", "没有可导出的手机号码")
                    return
        except Exception as e:
            print(f"重新加载号码失败: {e}")
            QMessageBox.critical(self, "导出错误", f"加载号码失败: {str(e)}")
            return
        
        # 如果没有选择特殊导出方式，使用默认导出
        if not (export_by_city or export_by_operator or export_by_duplicate):
            file_path, _ = QFileDialog.getSaveFileName(self, "保存文件", "", "CSV文件 (*.csv);;文本文件 (*.txt)")
            
            if file_path:
                try:
                    if file_path.endswith('.csv'):
                        df = pd.DataFrame(self.current_phones, columns=['phone_number'])
                        df.to_csv(file_path, index=False, encoding='utf-8-sig')
                    else:
                        with open(file_path, 'w', encoding='utf-8') as f:
                            for phone in self.current_phones:
                                f.write(phone + '\n')
                    
                    QMessageBox.information(self, "导出成功", f"号码已导出到: {file_path}")
                    
                except Exception as e:
                    QMessageBox.critical(self, "导出错误", f"导出文件时出错: {str(e)}")
        else:
            # 选择导出目录
            export_dir = QFileDialog.getExistingDirectory(self, "选择导出目录")
            
            if export_dir:
                try:
                    # 按城市导出
                    if export_by_city:
                        self.export_by_city(export_dir)
                    
                    # 按运营商导出
                    if export_by_operator:
                        self.export_by_operator(export_dir)
                    
                    # 按重复次数导出
                    if export_by_duplicate:
                        self.export_by_duplicate(export_dir)
                    
                    QMessageBox.information(self, "导出成功", f"号码已导出到: {export_dir}")
                    
                except Exception as e:
                    QMessageBox.critical(self, "导出错误", f"导出文件时出错: {str(e)}")
    
    def query_phone(self):
        """查询手机号码详细信息"""
        phone = self.query_edit.text().strip()
        
        # 验证输入
        if not PhoneValidator.is_valid_phone(phone):
            QMessageBox.warning(self, "查询错误", "请输入有效的11位手机号码")
            return
        
        try:
            # 获取号码前7位用于查询
            prefix = phone[:7]
            
            # 连接系统数据库查询详细信息
            conn = sqlite3.connect(self.db_manager.system_sqlite_path)
            cursor = conn.cursor()
            
            # 查询匹配的号码段信息
            cursor.execute('''
                SELECT segment, province, city, operator, area_code, zip_code 
                FROM phone_segments 
                WHERE segment LIKE ? || '%'
                LIMIT 1
            ''', (prefix,))
            
            result = cursor.fetchone()
            conn.close()
            
            if result:
                segment, province, city, operator, area_code, zip_code = result
                # 同时获取运营商信息（可能更准确）
                operator_info = PhoneValidator.get_operator(phone)
                
                # 显示查询结果
                result_text = (
                    f"手机号码: {phone}\n"
                    f"归属地: {province}-{city}\n"
                    f"运营商: {operator_info}\n"
                    f"号段: {segment}\n"
                    f"区号: {area_code}\n"
                    f"邮编: {zip_code}"
                )
                QMessageBox.information(self, "查询结果", result_text)
                self.query_result_label.setText(f"查询成功: {province}-{city} - {operator_info}")
            else:
                # 如果数据库查询失败，使用基本验证
                operator = PhoneValidator.get_operator(phone)
                city = PhoneValidator.get_city(phone)
                
                result_text = (
                    f"手机号码: {phone}\n"
                    f"归属地: {city}\n"
                    f"运营商: {operator}\n"
                    f"注: 数据库中未找到完整信息"
                )
                QMessageBox.information(self, "查询结果", result_text)
                self.query_result_label.setText(f"查询成功: {city} - {operator}")
                
        except Exception as e:
            QMessageBox.critical(self, "查询错误", f"查询时出错: {str(e)}")
            self.query_result_label.setText("查询失败")
    
    def export_by_city(self, export_dir):
        """按城市导出（高效优化版：减少数据库查询，提高内存使用效率）"""
        # 创建进度对话框
        progress_dialog = ProgressDialog(self, "按城市导出中...")
        progress_dialog.show()
        
        try:
            # 创建主目录
            main_city_dir = os.path.join(export_dir, "按城市导出")
            os.makedirs(main_city_dir, exist_ok=True)
            
            # 连接数据库
            conn = sqlite3.connect(self.db_manager.user_db_path)
            cursor = conn.cursor()
            
            # 批量预加载号码段-城市映射关系，减少重复查询
            prefix_city_map = self._load_prefix_city_map()
            
            # 确定要查询的表
            if self.current_data_type == 'generated':
                # 查询生成号码总数
                cursor.execute("SELECT COUNT(*) FROM generated_numbers")
                total_count = cursor.fetchone()[0]
                # 定义查询SQL
                query = "SELECT phone_number FROM generated_numbers ORDER BY id LIMIT ? OFFSET ?"
                table_type = 'single_generated'
            elif self.current_data_type == 'imported':
                # 查询导入号码总数
                cursor.execute("SELECT COUNT(*) FROM phone_numbers")
                total_count = cursor.fetchone()[0]
                # 定义查询SQL
                query = "SELECT phone_number FROM phone_numbers ORDER BY id LIMIT ? OFFSET ?"
                table_type = 'single_imported'
            else:
                # 查询两个表的总数
                cursor.execute("SELECT COUNT(*) FROM generated_numbers")
                generated_count = cursor.fetchone()[0]
                cursor.execute("SELECT COUNT(*) FROM phone_numbers")
                imported_count = cursor.fetchone()[0]
                total_count = generated_count + imported_count
                # 定义查询SQL
                query = '''
                    SELECT phone_number FROM (
                        SELECT phone_number, id, 1 as source FROM generated_numbers
                        UNION ALL
                        SELECT phone_number, id, 2 as source FROM phone_numbers
                    ) combined
                    ORDER BY id
                    LIMIT ? OFFSET ?
                '''
                table_type = 'combined'
            
            progress_dialog.update_progress(5, "准备数据中... 5%")
            QApplication.processEvents()
            
            # 统计所有城市
            city_files = {}
            city_counts = {}
            
            # 获取所有可能的城市并预创建文件
            cities = list(set(prefix_city_map.values()))
            if "未知城市" not in cities:
                cities.append("未知城市")
                
            # 创建文件句柄，不创建城市子目录
            for city in cities:
                # 直接在主目录下生成带城市名的文件
                file_path = os.path.join(main_city_dir, f"{city}_手机号码.txt")
                city_files[city] = open(file_path, 'w', encoding='utf-8-sig')
                city_counts[city] = 0
            
            progress_dialog.update_progress(10, "准备完成... 10%")
            QApplication.processEvents()
            
            # 大幅增加批次大小以减少数据库交互次数
            batch_size = 50000  # 每批处理的号码数增加到50000
            processed_count = 0
            offset = 0
            
            # 一次性处理所有号码，按城市分文件写入
            while True:
                # 执行查询
                cursor.execute(query, (batch_size, offset))
                batch_phones = [row[0] for row in cursor.fetchall()]
                
                if not batch_phones:
                    break
                
                # 批量处理当前批次的号码
                batch_city_groups = {}
                
                # 先将号码按城市分组
                for phone in batch_phones:
                    prefix = phone[:7]  # 获取前7位
                    # 使用预加载的映射快速获取城市
                    city = prefix_city_map.get(prefix, "未知城市")
                    
                    if city not in batch_city_groups:
                        batch_city_groups[city] = []
                    batch_city_groups[city].append(phone)
                
                # 批量写入每个城市的文件
                for city, phones in batch_city_groups.items():
                    if city in city_files:
                        # 批量写入，减少I/O操作
                        city_files[city].write('\n'.join(phones))
                        city_files[city].write('\n')
                        city_counts[city] += len(phones)
                
                # 更新进度
                processed_count += len(batch_phones)
                progress = 10 + int(min(90, (processed_count / total_count) * 90))
                progress_dialog.update_progress(progress, 
                    f"正在处理... {processed_count}/{total_count} 个号码 ({progress}%)")
                QApplication.processEvents()
                
                # 处理下一批
                offset += batch_size
            
            # 关闭所有文件句柄
            for file_handle in city_files.values():
                file_handle.close()
            
            conn.close()
            
            # 清理空文件
            for city in cities:
                file_path = os.path.join(main_city_dir, f"{city}_手机号码.txt")
                if os.path.exists(file_path) and os.path.getsize(file_path) == 0:
                    os.remove(file_path)
            
            progress_dialog.update_progress(100, "导出完成... 100%")
            QApplication.processEvents()
            
        except Exception as e:
            # 确保在异常情况下关闭所有文件
            if 'city_files' in locals():
                for file_handle in city_files.values():
                    try:
                        file_handle.close()
                    except:
                        pass
            progress_dialog.close()
            raise e
        
        finally:
            progress_dialog.close()
    
    def _load_prefix_city_map(self):
        """批量加载号码段到城市的映射，减少重复查询"""
        prefix_city_map = {}
        try:
            conn = sqlite3.connect(self.db_manager.system_sqlite_path)
            cursor = conn.cursor()
            
            # 查询所有号码段和对应的城市信息
            cursor.execute("SELECT segment, city FROM phone_segments")
            results = cursor.fetchall()
            
            # 构建映射字典
            for segment, city in results:
                prefix_city_map[segment] = city
            
            conn.close()
        except Exception as e:
            print(f"加载号码段映射失败: {e}")
        
        return prefix_city_map
    
    def export_by_operator(self, export_dir):
        """按运营商导出"""
        # 创建进度对话框
        progress_dialog = ProgressDialog(self, "按运营商导出中...")
        progress_dialog.show()
        
        try:
            # 第一阶段：统计运营商分组
            operator_phones = {}
            total_phones = len(self.current_phones)
            
            for i, phone in enumerate(self.current_phones):
                # 获取号码运营商信息
                operator = PhoneValidator.get_operator(phone)
                if operator not in operator_phones:
                    operator_phones[operator] = []
                operator_phones[operator].append(phone)
                
                # 更新进度
                progress = int((i + 1) / total_phones * 100)
                progress_dialog.update_progress(progress, f"正在分析运营商信息... {progress}%")
                QApplication.processEvents()  # 确保UI响应
            
            # 创建主目录
            main_operator_dir = os.path.join(export_dir, "按运营商导出")
            os.makedirs(main_operator_dir, exist_ok=True)
            
            # 第二阶段：导出文件
            total_operators = len(operator_phones)
            for i, (operator, phones) in enumerate(operator_phones.items()):
                # 创建运营商文件夹
                operator_dir = os.path.join(main_operator_dir, operator)
                os.makedirs(operator_dir, exist_ok=True)
                
                # 导出文件
                file_path = os.path.join(operator_dir, f"{operator}_手机号码.txt")
                with open(file_path, 'w', encoding='utf-8-sig') as f:  # 使用utf-8-sig支持Excel打开
                    # 批量写入以提高性能
                    f.write('\n'.join(phones))
                    f.write('\n')
                
                # 更新进度
                progress = 50 + int((i + 1) / total_operators * 50)  # 第二阶段进度从50%开始
                progress_dialog.update_progress(progress, f"正在导出{operator}的号码... {progress}%")
                QApplication.processEvents()  # 确保UI响应
        
        except Exception as e:
            progress_dialog.close()
            raise e
        
        finally:
            progress_dialog.close()
    
    def export_by_duplicate(self, export_dir):
        """按重复次数导出"""
        # 创建进度对话框
        progress_dialog = ProgressDialog(self, "按重复次数导出中...")
        progress_dialog.show()
        
        try:
            from collections import Counter
            
            # 更新进度
            progress_dialog.update_progress(10, "正在统计重复次数... 10%")
            QApplication.processEvents()  # 确保UI响应
            
            # 统计重复次数
            phone_counts = Counter(self.current_phones)
            
            progress_dialog.update_progress(30, "正在分组重复次数... 30%")
            QApplication.processEvents()  # 确保UI响应
            
            # 按重复次数分组
            duplicate_groups = {}
            for phone, count in phone_counts.items():
                if count not in duplicate_groups:
                    duplicate_groups[count] = []
                duplicate_groups[count].append(phone)
            
            progress_dialog.update_progress(50, "开始导出文件... 50%")
            QApplication.processEvents()  # 确保UI响应
            
            # 导出文件 - 直接放在export_dir中，不创建新目录
            total_groups = len(duplicate_groups)
            for i, (count, phones) in enumerate(duplicate_groups.items()):
                # 直接在导出目录中创建文件
                file_path = os.path.join(export_dir, f"重复{count}次_手机号码.txt")
                with open(file_path, 'w', encoding='utf-8-sig') as f:  # 使用utf-8-sig支持Excel打开
                    # 批量写入以提高性能
                    f.write('\n'.join(phones))
                    f.write('\n')
                
                # 更新进度
                progress = 50 + int((i + 1) / total_groups * 50)  # 第二阶段进度从50%开始
                progress_dialog.update_progress(progress, f"正在导出重复{count}次的号码... {progress}%")
                QApplication.processEvents()  # 确保UI响应
        
        except Exception as e:
            progress_dialog.close()
            raise e
        
        finally:
            progress_dialog.close()

def main():
    app = QApplication(sys.argv)
    
    # 设置应用程序字体
    font = QFont("Microsoft YaHei", 10)
    app.setFont(font)
    
    window = PhoneGeneratorApp()
    window.show()
    
    sys.exit(app.exec())

if __name__ == "__main__":
    main()